From 16522afca4eb4d4d7489f29796e6fd0ae2fb57bf Mon Sep 17 00:00:00 2001 From: david Date: Fri, 2 May 2025 13:22:10 +0200 Subject: [PATCH] . --- packages/eslint-config/README.md | 3 - packages/eslint-config/base.js | 115 +++++++++++++++++++++++ packages/eslint-config/compat.js | 13 +++ packages/eslint-config/express.js | 75 +++++++++++++++ packages/eslint-config/library.js | 34 ------- packages/eslint-config/next.js | 81 ++++++++++++++++ packages/eslint-config/package.json | 35 +++++-- packages/eslint-config/react-internal.js | 63 ++++++------- packages/eslint-config/server.js | 78 --------------- packages/eslint-config/vite.js | 19 ---- 10 files changed, 338 insertions(+), 178 deletions(-) delete mode 100644 packages/eslint-config/README.md create mode 100644 packages/eslint-config/base.js create mode 100644 packages/eslint-config/compat.js create mode 100644 packages/eslint-config/express.js delete mode 100644 packages/eslint-config/library.js create mode 100644 packages/eslint-config/next.js delete mode 100644 packages/eslint-config/server.js delete mode 100644 packages/eslint-config/vite.js diff --git a/packages/eslint-config/README.md b/packages/eslint-config/README.md deleted file mode 100644 index 8b42d90..0000000 --- a/packages/eslint-config/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# `@turbo/eslint-config` - -Collection of internal eslint configurations. diff --git a/packages/eslint-config/base.js b/packages/eslint-config/base.js new file mode 100644 index 0000000..97c2906 --- /dev/null +++ b/packages/eslint-config/base.js @@ -0,0 +1,115 @@ +import { fixupPluginRules } from "@eslint/compat"; +import eslint from "@eslint/js"; +import eslintConfigPrettier from "eslint-config-prettier"; +import _import from "eslint-plugin-import"; +import perfectionist from "eslint-plugin-perfectionist"; +import prettier from "eslint-plugin-prettier"; +import globals from "globals"; +import tseslint from "typescript-eslint"; + +import flatCompat from "./compat.js"; + +const tsConfig = /** @type {import("eslint").Linter.Config[]} */ (tseslint.configs.strict); + +/** @type {import("eslint").Linter.Config[]} */ +export default [ + eslint.configs.recommended, + ...tsConfig, + eslintConfigPrettier.rules, + perfectionist.configs["recommended-natural"], + ...flatCompat.plugins("eslint-plugin-only-warn"), + { + languageOptions: { + globals: { + ...globals.node, + JSX: true, + React: true, + }, + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + }, + }, + plugins: { + "@typescript-eslint": tseslint.plugin, + import: fixupPluginRules(_import), + prettier, + }, + }, + { + ignores: [ + ".*.?(c)js", + "*.config*.?(c)js", + ".*.ts", + "*.config*.ts", + "*.d.ts", + "dist", + ".git", + "node_modules", + "build", + ".next", + "*rollup*", + ], + }, + { + rules: { + "@typescript-eslint/consistent-type-imports": [ + "warn", + { + fixStyle: "inline-type-imports", + prefer: "type-imports", + }, + ], + "@typescript-eslint/naming-convention": [ + "warn", + { + format: ["PascalCase"], + selector: "typeLike", + }, + ], + "@typescript-eslint/no-unused-vars": [ + "warn", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + "arrow-body-style": "off", + "import/no-anonymous-default-export": "off", + "no-duplicate-imports": "error", + "no-unused-vars": "off", + "perfectionist/sort-objects": [ + "error", + { + type: "alphabetical", + }, + ], + "prefer-arrow-callback": "off", + "prettier/prettier": [ + "error", + { + endOfLine: "lf", + printWidth: 80, + semi: true, + singleQuote: false, + tabWidth: 2, + trailingComma: "all", + }, + ], + }, + settings: { + "import/parsers": { + "@typescript-eslint/parser": [".ts", ".tsx"], + }, + "import/resolver": { + node: { + extensions: [".js", ".jsx", ".ts", ".tsx"], + }, + typescript: { + alwaysTryTypes: true, + project: ["./tsconfig.json"], + }, + }, + }, + }, +]; diff --git a/packages/eslint-config/compat.js b/packages/eslint-config/compat.js new file mode 100644 index 0000000..780debb --- /dev/null +++ b/packages/eslint-config/compat.js @@ -0,0 +1,13 @@ +import { FlatCompat } from "@eslint/eslintrc"; +import path from "path"; +import { fileURLToPath } from "url"; + +// mimic CommonJS variables -- not needed if using CommonJS +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, // optional; default: process.cwd() +}); + +export default compat; diff --git a/packages/eslint-config/express.js b/packages/eslint-config/express.js new file mode 100644 index 0000000..9de7e66 --- /dev/null +++ b/packages/eslint-config/express.js @@ -0,0 +1,75 @@ +import globals from "globals"; +import tseslint from "typescript-eslint"; + +import baseConfig from "./base.js"; + +/** @type {import("eslint").Linter.Config[]} */ +export default [ + ...baseConfig, + { + languageOptions: { + globals: { + ...globals.node, + Express: true, + }, + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + }, + }, + plugins: { + "@typescript-eslint": tseslint.plugin, + }, + rules: { + "@typescript-eslint/consistent-type-imports": [ + "warn", + { + fixStyle: "inline-type-imports", + prefer: "type-imports", + }, + ], + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-floating-promises": ["error", { ignoreVoid: true }], + // TypeScript specific rules + "@typescript-eslint/no-misused-promises": [ + "error", + { + checksVoidReturn: false, + }, + ], + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unused-vars": [ + "warn", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + + "@typescript-eslint/require-await": "off", + "import/no-default-export": "off", + "import/prefer-default-export": "off", + // Express and Node specific rules + "no-console": ["warn", { allow: ["warn", "error"] }], + + "no-process-env": "off", + // Error handling + "no-unused-vars": "error", + }, + settings: { + "import/parsers": { + "@typescript-eslint/parser": [".ts"], + }, + "import/resolver": { + node: { + extensions: [".js", ".ts"], + }, + typescript: { + alwaysTryTypes: true, + project: ["./tsconfig.json"], + }, + }, + }, + }, +]; diff --git a/packages/eslint-config/library.js b/packages/eslint-config/library.js deleted file mode 100644 index 9b59cc0..0000000 --- a/packages/eslint-config/library.js +++ /dev/null @@ -1,34 +0,0 @@ -const { resolve } = require("node:path"); - -const project = resolve(process.cwd(), "tsconfig.json"); - -/** @type {import("eslint").Linter.Config} */ -module.exports = { - extends: ["eslint:recommended", "prettier", "turbo"], - plugins: ["only-warn"], - globals: { - React: true, - JSX: true, - }, - env: { - node: true, - }, - settings: { - "import/resolver": { - typescript: { - project, - }, - }, - }, - ignorePatterns: [ - // Ignore dotfiles - ".*.js", - "node_modules/", - "dist/", - ], - overrides: [ - { - files: ["*.js?(x)", "*.ts?(x)"], - }, - ], -}; diff --git a/packages/eslint-config/next.js b/packages/eslint-config/next.js new file mode 100644 index 0000000..dcca30a --- /dev/null +++ b/packages/eslint-config/next.js @@ -0,0 +1,81 @@ +import { fixupConfigRules } from "@eslint/compat"; +import next from "@next/eslint-plugin-next"; +import globals from "globals"; +import tseslint from "typescript-eslint"; + +import baseConfig from "./base.js"; +import flatCompat from "./compat.js"; + +const nextConfig = /** @type {import("eslint").Linter.Config[]} */ ( + fixupConfigRules( + /** @type {import("@eslint/compat").FixupConfigArray} */ + (flatCompat.config(next.configs["core-web-vitals"])) + ) +); + +/** @type {import("eslint").Linter.Config[]} */ +export default [ + ...baseConfig, + ...nextConfig, + { + languageOptions: { + globals: { + ...globals.node, + ...globals.browser, + JSX: true, + React: true, + }, + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + }, + }, + plugins: { + "@typescript-eslint": tseslint.plugin, + next, + }, + rules: { + // Next.js specific rules + "@next/next/no-html-link-for-pages": "off", + "@next/next/no-img-element": "off", + // TypeScript specific rules + "@typescript-eslint/array-type": "off", + "@typescript-eslint/consistent-type-definitions": "off", + + "@typescript-eslint/consistent-type-imports": [ + "warn", + { + fixStyle: "inline-type-imports", + prefer: "type-imports", + }, + ], + "@typescript-eslint/no-empty-function": "off", + + // Import/Export rules + "import/no-default-export": "off", + "import/prefer-default-export": "off", + + "react/display-name": "off", + "react/prop-types": "off", + // React specific rules + "react/react-in-jsx-scope": "off", + }, + settings: { + "import/parsers": { + "@typescript-eslint/parser": [".ts", ".tsx"], + }, + "import/resolver": { + node: { + extensions: [".js", ".jsx", ".ts", ".tsx"], + }, + typescript: { + alwaysTryTypes: true, + project: ["./tsconfig.json"], + }, + }, + react: { + version: "detect", + }, + }, + }, +]; diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index 0c93275..ae4df7f 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -1,20 +1,35 @@ { "name": "@repo/eslint-config", - "version": "0.0.0", + "version": "0.0.1", "private": true, + "main": "./base.js", + "type": "module", + "exports": { + "./base": "./base.js", + "./next": "./next.js", + "./express": "./express.js", + "./react-internal": "./react-internal.js" + }, "files": [ - "library.js", - "react-internal.js", - "server.js", - "vite.js" + "next.js", + "express.js", + "base.js", + "react-internal.js" ], "devDependencies": { - "@typescript-eslint/eslint-plugin": "^8.31.0", - "@typescript-eslint/parser": "^8.31.0", - "eslint-config-prettier": "^10.1.2", - "eslint-config-turbo": "^2.5.2", + "@eslint/js": "^9.24.0", + "@eslint/compat": "^1.2.8", + "@eslint/eslintrc": "^3.3.1", + "@typescript-eslint/eslint-plugin": "^8.29.0", + "@typescript-eslint/parser": "^8.29.0", + "globals": "^16.0.0", + "eslint-plugin-prettier": "^5.2.6", "eslint-plugin-import": "^2.31.0", + "eslint-plugin-security": "^3.0.1", + "eslint-config-prettier": "^10.1.1", + "@next/eslint-plugin-next": "^15.2.4", + "eslint-plugin-perfectionist": "^4.11.0", "eslint-plugin-only-warn": "^1.1.0", - "typescript": "5.8.3" + "typescript-eslint": "^8.29.0" } } diff --git a/packages/eslint-config/react-internal.js b/packages/eslint-config/react-internal.js index bf0a208..a82a25c 100644 --- a/packages/eslint-config/react-internal.js +++ b/packages/eslint-config/react-internal.js @@ -1,39 +1,34 @@ -const { resolve } = require("node:path"); +import globals from "globals"; +import tseslint from "typescript-eslint"; -const project = resolve(process.cwd(), "tsconfig.json"); +import baseConfig from "./base.js"; -/* - * This is a custom ESLint configuration for use with - * internal (bundled by their consumer) libraries - * that utilize React. - */ - -/** @type {import("eslint").Linter.Config} */ -module.exports = { - extends: ["eslint:recommended", "prettier", "turbo"], - plugins: ["only-warn"], - globals: { - React: true, - JSX: true, - }, - env: { - browser: true, - }, - settings: { - "import/resolver": { - typescript: { - project, +/** @type {import("eslint").Linter.Config[]} */ +export default [ + ...baseConfig, + { + languageOptions: { + globals: { + ...globals.browser, + JSX: true, + React: true, + }, + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + }, + }, + plugins: { + "@typescript-eslint": tseslint.plugin, + }, + rules: { + "react/prop-types": "off", + "react/react-in-jsx-scope": "off", + }, + settings: { + react: { + version: "detect", }, }, }, - ignorePatterns: [ - // Ignore dotfiles - ".*.js", - "node_modules/", - "dist/", - ], - overrides: [ - // Force ESLint to detect .tsx files - { files: ["*.js?(x)", "*.ts?(x)"] }, - ], -}; +]; diff --git a/packages/eslint-config/server.js b/packages/eslint-config/server.js deleted file mode 100644 index 3329c3f..0000000 --- a/packages/eslint-config/server.js +++ /dev/null @@ -1,78 +0,0 @@ -const { rules } = require("eslint-config-prettier"); - -module.exports = { - parser: "@typescript-eslint/parser", - plugins: ["@typescript-eslint", "sort-class-members"], - extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"], - env: { - browser: false, - node: true, - es6: true, - }, - parserOptions: { - ecmaVersion: "latest", - sourceType: "module", - }, - overrides: [ - { - files: ["**/__tests__/**/*"], - env: { - jest: true, - }, - }, - ], - rules: { - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-inferrable-types": "off", - "@typescript-eslint/no-empty-interface": "off", - "@typescript-eslint/recommended-requiring-type-checking": "off", - "@typescript-eslint/no-unused-vars": "warn", - "lines-between-class-members": ["error", "always", { exceptAfterSingleLine: true }], - - "sort-class-members/sort-class-members": [ - 2, - { - order: [ - "[static-properties]", - "[static-methods]", - "[conventional-private-properties]", - "[properties]", - "constructor", - "[methods]", - "[conventional-private-methods]", - ], - accessorPairPositioning: "getThenSet", - }, - ], - "@typescript-eslint/no-unused-vars": [ - "warn", - { argsIgnorePattern: "^_", varsIgnorePattern: "^T$" }, - ], - "import/no-relative-parent-imports": "error", - "import/order": [ - "error", - { - groups: ["builtin", "external", "internal", ["parent", "sibling", "index"]], - pathGroups: [ - { - pattern: "@/**", - group: "internal", - }, - ], - pathGroupsExcludedImportTypes: ["builtin"], - "newlines-between": "always", - alphabetize: { - order: "asc", - caseInsensitive: true, - }, - }, - ], - }, - settings: { - "import/resolver": { - typescript: { - project, - }, - }, - }, -}; diff --git a/packages/eslint-config/vite.js b/packages/eslint-config/vite.js deleted file mode 100644 index 9417d1c..0000000 --- a/packages/eslint-config/vite.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - env: { - node: true, - }, - parser: "@typescript-eslint/parser", - extends: [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "prettier", - ], - plugins: ["@typescript-eslint"], - parserOptions: { - sourceType: "module", - ecmaVersion: 2020, - }, - rules: { - "@typescript-eslint/no-non-null-assertion": "off", - }, -};