Skip to content

Require Paired Calls

Error
small-rules/require-paired-calls

Enforces balanced opener/closer function calls across all execution paths

Diagnostic Messages

asyncViolation
Cannot use {{asyncType}} between '{{opener}}' and '{{closer}}' (requireSync: true)
conditionalOpener
Conditional opener '{{opener}}' at {{location}} may not have matching closer on all paths
maxNestingExceeded
Maximum nesting depth of {{max}} exceeded for paired calls
multipleOpeners
Multiple consecutive calls to '{{opener}}' without matching closers (allowMultipleOpeners: false)
robloxYieldViolation
Yielding function '{{yieldingFunction}}' auto-closes all profiles - subsequent '{{closer}}' will error
unexpectedCloser
Unexpected call to '{{closer}}' - expected one of: {{expected}}
unpairedCloser
Unexpected call to '{{closer}}' - no matching opener on stack
unpairedOpener
Unpaired call to '{{opener}}' - missing '{{closer}}' on {{paths}}
wrongOrder
Closer '{{closer}}' called out of order - expected to close '{{expected}}' but '{{actual}}' is still open

Configuration

This rule accepts one options object after the severity.

allowConditionalClosersOptional

Allow closer calls that appear only on some conditional paths.

allowMultipleOpenersOptional

Allow repeated opener calls before matching closer calls.

maxNestingDepthOptional

Maximum opener nesting depth before reporting; 0 disables the limit.

pairsOptional

Opener and closer call pairs that must stay balanced.

{
"jsPlugins": [
"@pobammer-ts/small-rules"
],
"rules": {
"small-rules/require-paired-calls": [
"error",
{
"allowConditionalClosers": false,
"allowMultipleOpeners": true,
"maxNestingDepth": 0,
"pairs": [
{
"alternatives": [
"finish"
],
"closer": "cleanup",
"opener": "setup",
"openerAlternatives": [
"begin"
],
"platform": "roblox",
"requireSync": false,
"yieldingFunctions": [
"task.wait"
]
}
]
}
]
}
}

Examples

Unpaired opener lacks closer
function test() {
debug.profilebegin("task");
doWork();
}
Paired opener and closer
function test() {
debug.profilebegin("task");
doWork();
debug.profileend();
}