Skip to content

Code Hygiene ​

Two independent commands that surface things worth a human's attention without ever changing code: empty-catch flags error handling that silently does nothing, todo-report collects the TODO/FIXME/HACK notes scattered across the codebase into one list. Both are read-only.

empty-catch ​

Finds catch blocks that do nothing with the error, or do so little the error is effectively swallowed anyway.

bash
devtoolz empty-catch [paths...] [options]

A fully empty catch (e) {} is the simple case — already caught by ESLint's no-empty. The real value is a catch whose body is nothing but console.* calls (any method — console.debug/console.info swallow the error exactly as much as console.log does) and nothing else: no throw, no write to an outer-scope variable, no meaningful return. Syntactically that's completely valid code, so an ordinary lint rule can't catch it — it takes a semantic check, not a syntactic one.

Real output — a catch block that only logs the error:

Scanned 1 file.

1 problem found:
  src/example.ts:4:5  console-only  only logged, never handled — silently swallowed either way

Comments exempt a finding ​

A comment inside the catch block — found via a real token scan, not text matching, so a // inside a string never confuses it — removes the finding from the report, the same principle ESLint's no-empty already uses for a documented empty block:

ts
try {
  await api.save(draft)
} catch (e) {
  // best-effort autosave — a failed one just means the user's next
  // keystroke retries it, nothing to surface to them
}

This doesn't get reported — the comment is treated as the human having already made the call, not as something still needing a decision.

.vue files ​

The <script> block is checked through the same TypeScript-parser path as any other file — the same convention console-strip and the rest of the toolbox use for Vue single-file components.

Options ​

[paths...] ​

Files/directories to process (default: current directory).

--cwd <path> ​

Root paths are resolved against.

--ext <list> ​

Comma-separated extensions to include. Default: .ts,.tsx,.js,.jsx,.cjs,.mjs,.vue.

--ignore <glob> ​

Extra ignore pattern (repeatable) on top of the built-in defaults.

--no-respect-gitignore ​

Don't also honor the project's .gitignore.

Deliberately no --fix — there's no single correct way to actually handle an error, the decision is left to a human.

Example:

bash
devtoolz empty-catch src              # scan a directory
devtoolz empty-catch src --json       # machine-readable output

todo-report ​

Summarizes TODO/FIXME/HACK comments across the project — file:line plus the note's actual text.

bash
devtoolz todo-report [paths...] [options]

Comments are found the same way as everywhere else in the toolbox — a real tokenizer pass, with every string/template/regex/JSX text span masked first — so a line like const s = "TODO: not a real one" is never mistaken for a note. A tag matches as its own word anywhere in a comment (// see TODO above counts, same as most editors' own TODO highlighters), case-insensitively — but the report always shows the tag exactly as configured, not whatever casing happened to appear in the source.

Real output — a TODO wrapped across several // lines, and a one-line FIXME:

Scanned 2 files.

2 comments found (TODO: 1, FIXME: 1):
  src/notes.ts:1:4  TODO   TODO: this endpoint still uses the v1 auth header format — migrate to the bearer-token scheme once the backend team ships the v2 endpoint, see ticket INFRA-482 for the rollout plan
  src/notes.ts:8:4  FIXME  FIXME: race condition when two tabs save at once

Wrapped notes are joined back into one line ​

A real note is often written across several consecutive // lines, or one line of a /* */ block — only the first line has the tag. The command keeps absorbing subsequent lines of the same comment into the note's text as long as they're non-empty and don't themselves start a new tagged note, so the report shows the whole thought instead of cutting it off mid-sentence. The example above (src/notes.ts:1:4) is exactly that case — three physical // lines, one reported note.

--tags — which markers to look for ​

bash
devtoolz todo-report src --tags NOTE,REVIEW

Only the configured tags are matched — TODO/FIXME in the source are ignored entirely once --tags is set to something else:

Scanned 2 files.

Nothing found. Somebody already did their homework.

--max — a ratchet instead of a hard zero ​

A project that's knowingly living with some existing debt doesn't necessarily want every run to fail. --max <n> only fails once findings exceed that count:

Scanned 2 files.

2 comments found (TODO: 1, FIXME: 1):
  src/notes.ts:1:4  TODO   TODO: this endpoint still uses the v1 auth header format — migrate to the bearer-token scheme once the backend team ships the v2 endpoint, see ticket INFRA-482 for the rollout plan
  src/notes.ts:8:4  FIXME  FIXME: race condition when two tabs save at once

Within the configured limit (--max 5).

Without --max, the default is a hard 0 — any finding at all fails the run, the same simple default dead-exports uses.

.vue files ​

The <script> block goes through the same tokenizer path as any other file; <!-- --> comments inside <template> are matched by a line-aware scan, the same convention strip-comments uses for its own <template> handling — including the same known limitation: without a full SFC template parser, a <!-- -->-looking sequence inside a bound attribute string would be misread as a real comment.

Options ​

[paths...] ​

Files/directories to process (default: current directory).

--cwd <path> ​

Root paths are resolved against.

--tags <list> ​

Comma-separated tags to look for. Default: TODO,FIXME,HACK.

--max <n> ​

Don't fail unless findings exceed this count. Default: 0 (fail on any finding).

--ext <list> ​

Comma-separated extensions to include. Default: .ts,.tsx,.js,.jsx,.cjs,.mjs,.vue.

--ignore <glob> ​

Extra ignore pattern (repeatable) on top of the built-in defaults.

--no-respect-gitignore ​

Don't also honor the project's .gitignore.

Example:

bash
devtoolz todo-report src                   # default tags, fail on any finding
devtoolz todo-report src --tags NOTE       # only look for a custom tag
devtoolz todo-report src --max 20          # ratchet: fail only past 20 findings