litellm/ui/litellm-dashboard/eslint.config.mjs
ryan-crabbe-berri 67fce87b16
chore(ui): add filename, size, JSX-handler, prefer-const, and antd lint rules (#34341)
* chore(ui): add filename, size, JSX-handler, prefer-const, and antd lint rules

Wires up five error-level ESLint rules on the dashboard, grandfathering every
current offender into eslint-suppressions.json so the gate only bites new code
and ratchets down as files are fixed

- local/filename-pascal-case: new local rule requiring PascalCase .tsx names,
  exempting Next.js reserved files (page, layout, route, ...) and test/spec files
  (239 grandfathered)
- max-lines: 800 lines over src/**, excluding tests, src/data, and generated
  schema.d.ts (20 grandfathered)
- local/no-complex-jsx-arrow: new local rule flagging inline JSX arrow handlers
  with block bodies over two statements; each failure is a small extract-to-named
  -handler refactor (65 grandfathered)
- prefer-const: flipped from off to error (103 grandfathered)
- no-restricted-imports: added antd to the phase-out ban alongside tremor, and
  pointed both messages at shadcn/ui primitives (405 antd import sites grandfathered)

Both new local rules ship with RuleTester coverage

* fix(ui): preserve secondary extensions in filename-pascal-case suggestion

The suggestion text built the rename from only the head segment, so a
multi-dot file like my-component.utils.tsx was told to become
MyComponent.tsx instead of MyComponent.utils.tsx. Rebuild it from the
PascalCased head plus the untouched remaining segments, and add tests
covering multi-dot filenames and the hyphenated Next.js reserved names
(global-error, apple-icon, opengraph-image, twitter-image)
2026-07-22 19:34:35 -07:00

89 lines
2.8 KiB
JavaScript

import js from "@eslint/js";
import tseslint from "typescript-eslint";
import nextCoreWebVitals from "eslint-config-next/core-web-vitals";
import prettier from "eslint-config-prettier/flat";
import unusedImports from "eslint-plugin-unused-imports";
import local from "./scripts/eslint-rules/index.mjs";
const eslintConfig = [
{
ignores: [".next/**", "out/**", "build/**", "coverage/**", "next-env.d.ts", "src/lib/http/schema.d.ts"],
},
js.configs.recommended,
...tseslint.configs.recommended,
...nextCoreWebVitals,
prettier,
{
plugins: { "unused-imports": unusedImports, local },
rules: {
"unused-imports/no-unused-imports": "error",
"local/no-large-inline-object-arg": "warn",
"local/no-long-condition-chain": "warn",
"local/no-complex-jsx-arrow": ["error", { maxStatements: 2 }],
"@typescript-eslint/no-explicit-any": "warn",
"no-console": ["warn", { allow: ["warn", "error"] }],
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-unused-expressions": "off",
"@typescript-eslint/ban-ts-comment": "off",
"prefer-const": "error",
"no-empty": "off",
"no-prototype-builtins": "off",
"no-useless-catch": "off",
"no-useless-escape": "off",
"no-self-assign": "error",
"no-var": "error",
"no-nested-ternary": "error",
"react/no-danger": "error",
complexity: ["warn", 20],
"max-depth": ["warn", 4],
"max-params": ["error", 4],
"max-nested-callbacks": ["error", 4],
"no-restricted-syntax": [
"error",
{
selector: "CallExpression[callee.name='fetch']",
message:
"Raw fetch() is only allowed in src/lib/http/. Use the shared client (createApiClient / apiClient) from @/lib/http/client instead.",
},
],
"no-restricted-imports": [
"error",
{
patterns: [
{
group: ["@tremor/react", "@tremor/react/*"],
message:
"@tremor/react is being phased out; build new UI with shadcn/ui primitives instead of adding tremor imports.",
},
{
group: ["antd", "antd/*"],
message:
"antd is being phased out; build new UI with shadcn/ui primitives instead of adding antd imports.",
},
],
},
],
},
},
{
files: ["src/**/*.tsx"],
rules: {
"local/filename-pascal-case": "error",
},
},
{
files: ["src/**/*.{ts,tsx}"],
ignores: ["src/**/*.test.{ts,tsx}", "src/**/*.spec.{ts,tsx}", "src/data/**"],
rules: {
"max-lines": ["error", { max: 800, skipBlankLines: true, skipComments: true }],
},
},
{
files: ["src/lib/http/**"],
rules: {
"no-restricted-syntax": "off",
},
},
];
export default eslintConfig;