Skip to content

feat: add no-unrestricted-loop-in-serverless lint rule#56

Merged
danielchen0 merged 1 commit intomainfrom
danielchen0/no-unrestricted-loop-in-serverless
May 4, 2026
Merged

feat: add no-unrestricted-loop-in-serverless lint rule#56
danielchen0 merged 1 commit intomainfrom
danielchen0/no-unrestricted-loop-in-serverless

Conversation

@danielchen0
Copy link
Copy Markdown
Collaborator

Summary

  • Adds no-unrestricted-loop-in-serverless rule that detects unbounded loops (while(true), for(;;), while(1)) without a break or return in the loop body
  • These loops cause Vercel 300s timeouts in serverless functions — 21K+ timeouts/week in production
  • Smart about scope: doesn't count break inside nested loops/switches, or return inside nested arrow functions (e.g. .map() callbacks)
  • Allows loops that have proper exit conditions (break, return, bounded test)
  • Platform: backend only

Test plan

Scenario Expected
while (true) { await fetchData(); } (no break) Error flagged
for (;;) { await poll(); } (no break) Error flagged
while (1) { doWork(); } (no break) Error flagged
while (true) { if (done) break; } No error
while (true) { if (done) return data; } No error
for (let i = 0; i < 100; i++) { ... } No error
while (count < 10) { ... } No error
while (true) { for (...) { break; } } (break in nested loop) Error flagged (break doesn't exit outer)
while (true) { data.map(x => { return x; }) } (return in nested fn) Error flagged (return doesn't exit loop)

@daniel-chen-1
Copy link
Copy Markdown

daniel-chen-1 Bot commented Apr 28, 2026

Pushed an auto-fix commit to unblock the failing Lint & Format check (eslint @typescript-eslint/no-unnecessary-boolean-literal-compare in src/rules/no-unrestricted-loop-in-serverless.ts). CI should re-run shortly.

Copy link
Copy Markdown
Contributor

@lainterr lainterr Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed as steward. Approving — well-scoped.

Correctly handles:

  • while (true), while (1), for (;;), for (; true; )
  • hasBreakOrReturn walks up to confirm break/return belongs to this loop and not a nested loop or function

Non-blocking notes:

  1. do { ... } while (true) is not caught. Easy add — same hasBreakOrReturn check with a DoWhileStatement visitor.

  2. throw is not counted as a termination path. A loop that exits via throw new Error(...) will be flagged but is in fact bounded. Probably acceptable since throw-as-loop-exit is rare and arguably bad style.

  3. The platform tag is backend — good. Consider whether long-running web workers or service workers (web platform) deserve coverage too. They're not strictly serverless but unbounded loops there will hang the worker. Could be a follow-up rule with broader scope, since the message specifically says 'serverless' which would be misleading if applied to workers.

OK to ship as-is.

@daniel-chen-1
Copy link
Copy Markdown

daniel-chen-1 Bot commented May 3, 2026

Auto-fix: Lint & Format CI was failing on this rebase because README.md needed prettier formatting. Pushed prettier --write README.md as a follow-up commit. CI should go green on the next run.

Rebased onto main to resolve conflicts after #51 merge.
@daniel-chen-1 daniel-chen-1 Bot force-pushed the danielchen0/no-unrestricted-loop-in-serverless branch from 7997ed4 to 7b6e531 Compare May 4, 2026 16:24
@daniel-chen-1
Copy link
Copy Markdown

daniel-chen-1 Bot commented May 4, 2026

Rebased onto main after #51 merged — the conflicts were mechanical (rule-registration list, README rule table, rule-count assertion, meta.ts platform map), no logic touched. New head is 7b6e531, all 7 CI checks green, mergeable=true. Ready to merge when you are.

@danielchen0 danielchen0 merged commit 337c994 into main May 4, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant