require-paired-calls
Checks opener and closer call pairs across control flow.
Rule details Problem
Section titled “Rule details ”ProblemThe rule keeps a stack of configured opener calls and matches later closers against that stack.
It reports missing closers, extra closers, closers called out of order, early exits that skip cleanup, and branch paths
where an opener is not closed everywhere. When requireSync is on, it also reports await and yield between the
opener and closer.
With no options, it defaults to Roblox profiling rules:
- opener:
debug.profilebegin - closer:
debug.profileend requireSync: trueplatform: "roblox"- yielding functions:
task.wait,wait,*.WaitForChild,*.*Async
Examples
Section titled “Examples” Incorrect
function runTask() { debug.profilebegin("runTask"); if (!ready) return; debug.profileend();} Correct
function runTask() { debug.profilebegin("runTask"); try { doWork(); } finally { debug.profileend(); }}Options
Section titled “Options”| Option | Type | Default |
|---|---|---|
allowConditionalClosers | boolean | false |
allowMultipleOpeners | boolean | true |
maxNestingDepth | number | 0 |
pairs | PairConfiguration[] | default Roblox profiling pair when omitted |
Each pair supports these fields:
| Field | Type |
|---|---|
opener | string |
closer | string | string[] |
alternatives | string[] |
openerAlternatives | string[] |
platform | "roblox" |
requireSync | boolean |
yieldingFunctions | string[] |
Related rules
Section titled “Related rules” require-module-level-instantiation Keeps long-lived objects out of hot paths