no-console-in-command
Disallow console.* inside a CLI command handler; write through the output layer
Disallow
console.*inside a CLI command handler; write through the output layer.
- burgee requirement: O3 — command code writes through the output layer, never
console.*, so O1 (--json) and O2 (no decoration when not a TTY) are honoured - Hosts: commander (and
burgee/commander,@commander-js/extra-typings), yargs (andburgee/yargs), burgee - Recommended:
error
Why
--json and a quiet non-TTY mode only hold if every byte a command prints goes through one place that knows about them. A console.log inside a handler is a line of prose in the middle of a JSON document, and a colour code in a captured log. oclif/core #1644 shows the drift when this is not enforced.
Rule details
Reports a call on the global console that is lexically inside a proven command handler:
- commander: the function given to
.action()— inline, or a function declared in the same file and passed by name; - yargs: the handler of a
.command()registration (fourth argument, orhandlerin the object form); - burgee:
runon a command object.
Nested callbacks inside the handler are command code too (items.forEach((i) => console.log(i)) reports).
Not reported: console at module scope, in a hook (.hook('preAction', …)), in a yargs builder, in a helper defined outside the handler, or a local binding named console.
Incorrect
import { Command } from 'commander';
const program = new Command();
program.command('ls').action(async () => {
const items = await list();
console.log(items.join('\n'));
});import { defineCommand } from 'burgee';
defineCommand({
name: 'ls',
description: 'List',
effects: 'read_only',
run: async () => {
console.log(await list());
},
});Correct
// burgee: return the data. The engine renders it for a person and envelopes it for --json.
defineCommand({
name: 'ls',
description: 'List',
effects: 'read_only',
run: async () => ({ items: await list() }),
});
// commander / yargs: write through the one output module the program owns.
import { out } from './output.js';
program.command('ls').action(async () => out.result(await list()));Known limitations
- A helper called from the handler is not followed:
action(() => report())withreportwriting toconsoleis not reported. Following calls across functions is a data-flow question this rule does not ask. - A handler imported from another file is not read here — lint that file, where it is registered, or declare it with a host there.
Further reading
Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.