Consistency Checks
Two independent, read-only commands that share a foundation rather than a topic: both scan text/convention instead of parsing an AST, and both check whether one part of a project still matches another — scripts-check checks package.json's scripts against what README/CI actually invoke, orphan-tests checks a test file against the source it claims to cover.
scripts-check
Cross-checks package.json's scripts against README/docs and .github/workflows/*.yml — a mention of a script that doesn't exist, and, as a weaker signal, a script nothing documents.
devtoolz scripts-check [dir] [options]Real output — a README with a typo'd script name, and two real scripts nothing documents:
Checked 1 source against package.json's scripts.
3 problems found:
README.md:4 buld mentioned here, but not in package.json scripts
package.json:4 build in package.json scripts, but not mentioned anywhere checked
package.json:6 deploy in package.json scripts, but not mentioned anywhere checkedFix the typo (buld → build), and the first line disappears. Document — or don't — the other two; that direction is a judgment call, not a hard rule.
Two directions, two different bars for what counts as a mention
Direction 1 (a mentioned script that doesn't exist — the high-value one) only recognizes forms with an explicit run: npm run X/npm run-script X, yarn run X, pnpm run X, plus npm's own no-run-needed npm test/npm start. Without that explicit run, there's no way to tell yarn X (a script) from a real yarn subcommand (yarn add, yarn install) — extracting an arbitrary name from that shape would just be noise.
Direction 2 (a declared script nothing mentions — the weaker signal) can afford to also accept yarn/pnpm's own bare yarn X/pnpm X form, since it's checking one already-known name, not extracting an arbitrary one from free text. A clean run:
Checked 1 source against package.json's scripts.
Nothing to see here. Suspiciously clean, even.Reserved lifecycle scripts are exempt from direction 2
prepublishOnly, preinstall, postinstall, prepare, and any pre*/post* script that has a real peer script declared (prebuild when build exists) — npm runs these itself, documenting them "for a human" is pointless.
A CI step under its own working-directory: belongs to a different package.json
A demo/ subproject with its own package.json and its own test:e2e script, invoked from a CI job with working-directory: demo, is correctly understood as out of scope for the root package.json this command checks — not flagged as missing.
Options
[dir]
Package directory to check (default: .).
--file <path>
Markdown/doc file to check, relative to [dir] (repeatable) — default: README.md.
Example:
devtoolz scripts-check # package.json in the current directory
devtoolz scripts-check path/to/package # a specific directory
devtoolz scripts-check --file docs/deploying.md # check an additional docorphan-tests
Finds test files whose source disappeared — renamed or deleted, the test still green, testing nothing real anymore.
devtoolz orphan-tests [paths...] [options]Real output — parseQuery.ts was renamed/removed, its test survived:
Scanned 3 files.
1 orphan test found:
src/parseQuery.test.ts orphan no matching source found (tried .ts, .tsx, .js, .jsx, .mjs, .cjs, .vue)Reliable only under a simple naming convention
Co-located — Foo.test.ts next to Foo.ts — including one level down, in a sibling __tests__/tests/test/spec/specs directory (src/adapters/__tests__/http.test.ts next to src/adapters/http.ts). A clean run against that layout:
Scanned 2 files.
Nothing to see here. Suspiciously clean, even.Not every project follows either shape — one whose test names are descriptive rather than 1:1 with a source file (feature-component.test.ts testing components/feature.vue, say) is honestly outside what this command can check reliably, and will show noise under it. That's a stated limitation, not a bug to work around.
A mirrored layout — separate source and test roots
--source-dir/--test-dir (always given together) check a test's path against the same relative path under a different root, instead of the same directory:
Scanned 2 files.
1 orphan test found:
tests/legacyParser.test.ts orphan no matching source found (tried .ts, .tsx, .js, .jsx, .mjs, .cjs, .vue)Scenario/integration tests are a known false positive
A test exercising a combination of modules, or several behaviors of one component, with no single source file of its own (hydration.test.ts, ssr.test.ts — several angles on the same component) will always look orphaned under this command's strict per-file rule. --ignore <glob> is the documented way to exclude it — this command doesn't try to guess which mentions are "real" ones.
Options
[paths...]
Files/directories to process — co-located mode only (default: current directory).
--cwd <path>
Root paths are resolved against.
--ext <list>
Comma-separated extensions to consider as possible test files. Default: .ts,.tsx,.js,.jsx,.mjs,.cjs.
--test-suffix <list>
Comma-separated suffixes that mark a test file. Default: .test,.spec.
--source-ext <list>
Comma-separated extensions tried for a matching source file. Default: .ts,.tsx,.js,.jsx,.mjs,.cjs,.vue.
--source-dir <path> / --test-dir <path>
Mirrored layout — source root and test root, both relative to --cwd. Must be given together.
--ignore <glob>
Extra ignore pattern (repeatable) on top of the built-in defaults — the way to exclude a known scenario/integration test.
--no-respect-gitignore
Don't also honor the project's .gitignore.
Example:
devtoolz orphan-tests src # co-located, including __tests__/tests
devtoolz orphan-tests --source-dir src --test-dir tests # mirrored layout
devtoolz orphan-tests src --ignore src/integration.test.ts # exclude a known scenario test