no-inner-declarations

Disallow function and, optionally, var declarations in nested blocks

Outside strict mode, a function declared inside an if or a loop is also visible after the block, but it only has a value once the block has run. Whether a call works depends on which branch was taken.

In strict mode the function belongs to its block, like a let, so by default it isn't reported there. Modules and class bodies are always strict. That leaves CommonJS files and scripts without "use strict".

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"no-inner-declarations" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"no-inner-declarations" = [
  "error",
  "functions", # "functions" or "both"
  {
    blockScopedFunctions = "allow", # "allow" or "disallow"
  },
]

Examples#

logger.cjs1 problem
if (process.env.DEBUG) {
  function log(message) {
    console.log(message);
  }
}

log("ready"); // TypeError unless DEBUG is set
logger.cjsNo problems
function log(message) {
  if (process.env.DEBUG) {
    console.log(message);
  }
}

log("ready");

Not reported either, because the file is in strict mode and log stays in its block:

logger.cjsNo problems
"use strict";

if (process.env.DEBUG) {
  function log(message) {
    console.log(message);
  }
  log("ready");
}

Options#

bunfig.toml
[lint.rules]
no-inner-declarations = ["error", "both", { blockScopedFunctions = "disallow" }]

The first option says what to look at:

OptionWhat it does
"functions" (default)Report function declarations in nested blocks.
"both"Also report var declarations in nested blocks.

A var belongs to the whole function, no matter which block it's written in:

example.jswith "both"1 problem
if (user.isAdmin) {
  var role = "admin";
}
example.jswith "both"No problems
let role;
if (user.isAdmin) {
  role = "admin";
}

The second option is an object:

OptionDefaultWhat it does
blockScopedFunctions"allow"With "disallow", report functions in nested blocks in strict mode too.
namespaces"disallow"Only for an oxlint config, where the rule also reports declarations directly inside a TypeScript namespace. "allow" turns that off. bunfig.toml rejects this option.
example.jswith "functions", { "blockScopedFunctions": "disallow" }1 problem
if (process.env.DEBUG) {
  function log(message) {
    console.log(message);
  }
  log("ready");
}