@xklaim/warndog
v1.0.4
Published
A brutally honest senior engineer watching your JavaScript/Node.js code in real time
Maintainers
Readme
warndog
warndog is a JavaScript and Node.js code scanner with a CLI-first workflow for catching bug-prone async, logic, complexity, and error-handling patterns.
It supports:
- Project scans for
.js,.mjs,.cjs, and.jsx - Live watch mode for re-analysis on save
- Runtime instrumentation for catching async failures while a script runs
- JSON, Markdown, and HTML reports
- Config discovery via
cosmiconfig - A small plugin API for custom rules
Install
Use it globally as a CLI:
npm install -g warndog
warndog --helpOr keep it local to a project:
npm install --save-dev warndog
npx warndog .Node.js 16+ is required.
Quick Start
Create a starter config:
npx warndog initScan the current project:
npx warndog .Watch a directory and re-scan changed files:
npx warndog watch srcGenerate a report:
npx warndog report . --format markdown --output warndog-report.mdExplain warnings near a line:
npx warndog explain src/server.js:42Run a script with runtime instrumentation:
npx warndog run ./scripts/job.js -- --arg-one valueCLI
Default scan
warndog [target]Scans a file, directory, or glob. If omitted, the default target is ..
Common flags:
--config <path>: use a specific config file--ignore <patterns...>: append ignore globs--severity <level>: minimum severity to report--confidence <number>: minimum confidence to report--json: print JSON instead of the pretty formatter--debug: print extra debugging detail--quiet: suppress non-essential output--no-color: disable ANSI colors
Exit codes:
0: no high-severity findings1: at least onehighfinding2: at least onecriticalfinding
Subcommands
warndog scan [target]
- Full scan with optional
--depth,--include, and experimental--fix
warndog watch [target]
- Watches files and re-runs analysis on save
- Supports
--debounce <ms>
warndog run <script> [args...]
- Runs a Node.js script with the runtime interceptor preloaded
- Supports
--track-async,--track-nulls, and--timeout <ms>
warndog explain <file:line>
- Explains warnings near a file location
- Use
--rule <id>to explain a rule directly
warndog report [target]
- Writes a full report to disk
- Supports
--format json|html|markdownand--output <file>
warndog init
- Writes a starter
warndog.config.js - Supports
--force
Configuration
warndog searches for config with cosmiconfig in:
warndog.config.jswarndog.config.cjs.warndogrc.warndogrc.json.warndogrc.jspackage.json
Example:
/** @type {import('warndog').WarnDogConfig} */
module.exports = {
include: ['src/**/*.js', '*.js'],
ignore: [
'node_modules/**',
'dist/**',
'coverage/**',
'**/*.test.js',
],
severity: 'low',
confidence: 50,
complexity: {
cyclomaticThreshold: 10,
nestingThreshold: 4,
functionLengthMax: 80,
},
rules: {
'missing-await': 'high',
'floating-promise': 'high',
'cyclomatic-complexity': 'medium',
},
plugins: [
'warndog/plugins/react',
'./warndog.custom-plugin.js',
],
output: {
format: 'pretty',
color: true,
},
debug: false,
};Config Reference
include?: string[]: include globs to analyzeignore?: string[]: ignore globsseverity?: 'low' | 'medium' | 'high' | 'critical': minimum severityconfidence?: number: minimum confidence percentagerules?: Record<string, string | boolean | { severity: string }>: enable, disable, or override a rule severityplugins?: (string | Plugin)[]: plugin module names, deep imports, local paths, or inline plugin objectscomplexity?: { cyclomaticThreshold?: number; nestingThreshold?: number; functionLengthMax?: number }output?: { format?: 'pretty' | 'json'; color?: boolean }debug?: boolean
Built-In Rules
Async:
missing-awaitsilent-promisefloating-promise
Logic:
impossible-conditionaccidental-assignmentalways-truthy-falsyinconsistent-return
Variables:
shadowed-variableunused-criticalconst-mutation
Complexity:
cyclomatic-complexitydeep-nestingcallback-hell
Patterns:
risky-equalityerror-handling
Built-In Plugins
Two plugin modules ship with the package and can be referenced from config:
module.exports = {
plugins: [
'warndog/plugins/express',
'warndog/plugins/react',
],
};warndog/plugins/express adds:
express/missing-error-middlewareexpress/double-response
warndog/plugins/react adds:
react/setstate-in-renderreact/useeffect-missing-deps
Programmatic API
const { Engine, loadConfig, getAllRules } = require('warndog');
async function main() {
const config = await loadConfig();
const engine = new Engine(config);
const results = await engine.analyzeTarget('src');
console.log('rules:', getAllRules().length);
console.log(JSON.stringify(results, null, 2));
}
main().catch((error) => {
console.error(error);
process.exit(1);
});Main exports:
EngineloadConfigloadPluginscreatePlugincreateRulegetAllRules
Writing Plugins
Local plugins can be module paths or inline objects.
const { createPlugin, createRule } = require('warndog');
const noConsoleRule = createRule({
id: 'custom/no-console',
description: 'Detect console.log in application code',
defaultSeverity: 'low',
check({ ast }) {
const warnings = [];
const traverse = require('@babel/traverse').default;
const t = require('@babel/types');
traverse(ast, {
CallExpression(path) {
const callee = path.node.callee;
if (!t.isMemberExpression(callee)) return;
if (!t.isIdentifier(callee.object, { name: 'console' })) return;
if (!t.isIdentifier(callee.property, { name: 'log' })) return;
warnings.push({
line: path.node.loc?.start.line,
confidence: 95,
message: 'console.log left in application code',
suggestion: 'remove the call or route it through your logger',
});
},
});
return warnings;
},
});
module.exports = createPlugin({
name: 'custom-plugin',
rules: [noConsoleRule],
});Then reference it from warndog.config.js:
module.exports = {
plugins: ['./warndog.custom-plugin.js'],
};Plugin contract:
name: stringrules?: Rule[]setup?: (config) => void | Promise<void>
Rule contract:
id: stringdescription: stringdefaultSeverity: stringcheck(ctx)for per-file analysischeckAll(results, config)for cross-file analysis
Reports
warndog report supports three output formats:
json: machine-readable result payloadmarkdown: shareable text reporthtml: styled browser report
The JSON report includes:
versiontimestampsummary.totalsummary.bySeveritysummary.filesresults
Development
Install dependencies:
npm installUseful scripts:
npm run lint
npm test
npm run test:unit
npm run test:integration
npm run test:coverage
npm run pack:checknpm run pack:check performs a dry-run package build and prints the exact files that would be published.
Publish Checklist
Before publishing a new version:
- Update
versioninpackage.jsonor runnpm version patch|minor|major. - Run
npm run lint. - Run
npm test. - Run
npm run pack:check. - Review the generated file list and package size.
- Publish with
npm publishornpm publish --access publicfor a scoped public package.
The package includes a prepublishOnly safeguard that runs lint and tests during publish.
Package Contents
The published package intentionally includes only:
bin/src/plugins/index.d.ts- npm-standard metadata files such as
package.json,README.md, andLICENSE
Tests, local setup notes, and development-only files are excluded from the npm tarball.
License
MIT. See LICENSE.
