litellm/ui/litellm-dashboard/tests/eslint-rules/no-large-inline-object-arg.test.ts
ryan-crabbe-berri 5973d9fd2b
feat(ui): add eslint rules for nested ternaries, large inline object args, and long condition chains (#32415)
* feat(ui): add eslint rules for nested ternaries, large inline object args, and long condition chains

Adds three dashboard lint rules to keep new code readable. Nested ternaries
are banned outright via the built-in no-nested-ternary, with the 265 existing
occurrences grandfathered in eslint-suppressions.json so only new ones fail.

Two custom rules ship as a small local plugin under scripts/eslint-rules:
no-large-inline-object-arg flags object literals with 4+ properties passed
straight into a call, nudging toward a named variable, and no-long-condition-chain
flags boolean expressions that combine 4+ conditions, nudging toward a named
boolean. Both are warnings tracked on the existing budget ratchet
(eslint-budgets.json + eslint-metrics.json) with headroom above the current
counts, so they ratchet down over time rather than freezing a baseline. Both
thresholds are configurable rule options and covered by RuleTester unit tests.

* fix(ui): scope no-long-condition-chain to boolean operators, not nullish

Greptile flagged that the rule counted nullish-coalescing chains the same as
&&/|| chains, so a 4-part `a ?? b ?? c ?? d` fallback surfaced "Boolean
expression combines 4 conditions", which is inaccurate since a `??` fallback
is value defaulting, not a condition. Restrict the visitor to && / || nodes so
`??` chains are treated as leaves, while a boolean chain nested inside a `??`
is still caught. Drops 6 miscounted occurrences (240 -> 234).

* chore(ui): sync lint metrics and suppressions with staging

Merge advanced the base branch, adding one no-large-inline-object-arg
occurrence (508 -> 509) and making one grandfathered react-hooks suppression
stale. Regenerate eslint-metrics.json and prune the suppression so the
budget/drift gate passes.

* chore(ui): sync lint metrics with staging

Merge advanced the base, adding four no-large-inline-object-arg occurrences
(509 -> 513). Regenerate eslint-metrics.json so the drift gate passes.
2026-07-08 21:32:16 +00:00

46 lines
1.5 KiB
TypeScript

import { RuleTester } from "eslint";
import rule from "../../scripts/eslint-rules/no-large-inline-object-arg.mjs";
const ruleTester = new RuleTester({
languageOptions: { ecmaVersion: "latest", sourceType: "module" },
});
ruleTester.run("no-large-inline-object-arg", rule as never, {
valid: [
"foo({ a: 1, b: 2, c: 3 });",
"foo({});",
"const opts = { a: 1, b: 2, c: 3, d: 4 }; foo(opts);",
"const x = { a: 1, b: 2, c: 3, d: 4 };",
"function f() { return { a: 1, b: 2, c: 3, d: 4 }; }",
"const arr = [{ a: 1, b: 2, c: 3, d: 4 }];",
"foo(1, 2, { a: 1, b: 2 });",
{ code: "foo({ a: 1, b: 2, c: 3, d: 4 });", options: [{ minProperties: 5 }] },
],
invalid: [
{
code: "foo({ a: 1, b: 2, c: 3, d: 4 });",
errors: [{ messageId: "tooLarge", data: { count: 4 } }],
},
{
code: "new Widget({ a: 1, b: 2, c: 3, d: 4, e: 5 });",
errors: [{ messageId: "tooLarge", data: { count: 5 } }],
},
{
code: "foo(1, { a: 1, b: 2, c: 3, d: 4 });",
errors: [{ messageId: "tooLarge" }],
},
{
code: "foo({ a: 1, ...rest, c: 3, d: 4 });",
errors: [{ messageId: "tooLarge", data: { count: 4 } }],
},
{
code: "foo({ a: 1, b: 2, c: 3 });",
options: [{ minProperties: 3 }],
errors: [{ messageId: "tooLarge", data: { count: 3 } }],
},
{
code: "outer({ a: 1, b: 2, c: 3, d: 4 }, inner({ e: 5, f: 6, g: 7, h: 8 }));",
errors: [{ messageId: "tooLarge" }, { messageId: "tooLarge" }],
},
],
});