@studnicky/inline-trivial-logic
Disallows shim functions that only forward or delegate a value without adding logic. It examines an expression-bodied arrow, a single return, or the exact two-statement reduction var/let/const result = expression; return result; (leading empty statements are ignored). It can report a forwarded identifier, call, awaited expression, chain, or a non-this member expression. Correct remediation rewrites call sites and can change public or virtual dispatch semantics.
Fixable: No · Options: allowLiterals, allowMemberExpressions · Suggested severity: error
Exemptions
The rule leaves these shapes alone because they are a value, a contract boundary, or do not have a safe call-site rewrite:
- factories that create an object, array, or instance; member access rooted at
this; and a function returningthis; - literal and template-literal returns by default, and an identifier that selects one of multiple own parameters rather than forwarding a sole parameter;
- a function with a type-predicate return annotation;
- an inline function passed as a call or constructor argument, including through an object or array literal argument;
- a class function expression or arrow member mandated by an implemented/inherited member, or marked
protectedoroverride; - calls that read instance state through
thisor a#privatefield, or that call through a#private,private, orprotectedreceiver; - calls whose arguments are not literals or a one-to-one relay of the function's own parameters —
static withCeiling(strategy, ceilingMs) { return (attempt, base) => { const result = Math.min(ceilingMs, strategy(attempt, base)); return result; }; }callsMath.minwith a closed-over outer variable and the result of another call, neither a pass-through of the returned arrow's own parameters, so this is a decorator capping a strategy's output, not a shim;satisfiesConstant(value, constantValue) { return Predicates.areDeeplyEqual(value, constantValue); }passes both parameters straight through, unmodified, and stays reported; and - a direct call through a locally scoped receiver, where the wrapper preserves that receiver's method binding — a plain-identifier receiver whose own declaration is nested inside an enclosing function, rather than declared at module top level or resolved from a standard-library
.d.tsfile, holds a runtime-injected value: inpackages/resilience/src/retry/retry/Retry.ts:508-516, the private methodclassifyErrorholdsconst classifier = this.errorClassifier;, then whenclassifieris not itself a function returnsclassifier.classify(error, attemptNumber)— this cannot become a point-freeclassifier.classify, because that detaches the method from itsclassifierreceiver, and any implementation ofclassifyreadingthisinternally breaks the next time it runs. A statically-known receiver such asMath.abs(v)or a module-levelimportdoes not qualify — nothing is detached by inlining it — soMath.min/Predicates.areDeeplyEqual-shaped calls stay reported regardless of this exemption.
A public zero-argument this.method() call and a direct call that forwards only its own parameters remain reportable shims.
✗ Incorrect
// Trivial call-through
function getUser(id: string): Promise<User> {
return repository.findById(id);
}// Trivial identifier forward
const wrapValue = (v: string) => v;// Trivial await forward
async function fetchData(url: string): Promise<Data> {
return await http.get(url);
}// The explicit-return-binding spelling remains the same shim
function getUser(id: string): Promise<User> {
const result = repository.findById(id);
return result;
}✓ Correct
// Adds validation logic before delegating
function getUser(id: string): Promise<User> {
validateId(id);
return repository.findById(id);
}// Constructs a new object — not trivial
function createUser(name: string): User {
return new User(name);
}// Callback position has no call site to inline into
runWhenEnabled(() => service.refresh());// The arguments do work; they are not a one-to-one forward
function withLimit(value: number, limit: number): number {
return Math.min(value, limit - 1);
}// Default literal policy treats this function as the value it produces
function empty(): string {
return "";
}Options
{
"@studnicky/inline-trivial-logic": [
"error",
{
"allowLiterals": true,
"allowMemberExpressions": false
}
]
}| Option | Type | Default | Description |
|---|---|---|---|
allowLiterals | boolean | true | Allow functions that return a literal or template-literal value. Set false to report them. |
allowMemberExpressions | boolean | false | Allow functions that return a member expression (e.g. obj.prop). |