Deslop JavaScript code.
Finds unused files, dead exports, dead dependencies, circular imports, redundant aliases, duplicate types, and other DRY violations. Each finding carries a confidence tier so you can gate CI on the high-signal ones and treat the rest as code-review prompts.
npm install deslop-jsThe deslop-cli package provides a command-line interface:
npm install -g deslop-cli# scan the current directory
deslop
# scan a specific project
deslop ./my-project
# use the explicit analyze sub-command (equivalent to the above)
deslop analyze ./my-projectdeslop [root] [options]
# custom entry points
deslop --entry src/main.ts --entry src/worker.ts
# ignore test files
deslop --ignore "**/*.test.ts" --ignore "**/__mocks__/**"
# only scan specific extensions
deslop --extensions .ts .tsx
# resolve path aliases via tsconfig
deslop --tsconfig ./tsconfig.json
# include type-only exports in results
deslop --report-types
# report unused exports from entry files too
deslop --include-entry-exports
# output results as JSON (useful for CI or piping to other tools)
deslop --json
# exit with code 1 when unused code is found (for CI gates)
deslop --fail-on-issues
# exit with code 1 when circular imports are found
deslop --fail-on-cycles# fail the build if there are unused exports or circular imports
deslop ./src --fail-on-issues --fail-on-cycles --ignore "**/*.test.ts"import { analyze, defineConfig } from "deslop-js";
const config = defineConfig({ rootDir: "./my-project" });
const result = await analyze(config);
// unused-code findings (syntactic)
result.unusedFiles; // files unreachable from any entry point
result.unusedExports; // exported symbols never imported
result.unusedDependencies; // package.json deps not imported anywhere
result.circularDependencies; // import cycles
// redundancy / DRY findings (syntactic, on by default)
result.redundantAliases; // `import { x as x }`, useless re-export renames
result.duplicateExports; // same name exported twice from one module
result.duplicateImports; // same specifier imported multiple times
result.redundantTypePatterns; // `T & {}`, `Partial<Partial<T>>`, etc.
result.identityWrappers; // `const wrap = (x) => fn(x)`
result.duplicateTypeDefinitions; // same-shape type declared in N files
result.duplicateInlineTypes; // anonymous `{ a, b, c }` repeated across modules
result.simplifiableFunctions; // `() => { return x }`, `await x; return x`
result.simplifiableExpressions; // `!!x`, `x ? x : y`, `cond ? true : false`
result.duplicateConstants; // same literal value across files
// semantic findings (type-aware, opt-in via `semantic.enabled: true`)
result.unusedTypes; // type aliases / interfaces never referenced
result.unusedEnumMembers; // enum members no reference site uses
result.unusedClassMembers; // class members no caller invokes
result.misclassifiedDependencies; // `dependencies` entries used only as types
// diagnostics
result.analysisErrors; // structured errors from any pipeline stage
result.totalFiles;
result.totalExports;
result.analysisTimeMs;defineConfig accepts a required rootDir and optional overrides:
const config = defineConfig({
rootDir: "./my-project",
entryPatterns: ["src/main.ts"],
ignorePatterns: ["**/*.test.ts"],
tsConfigPath: "./tsconfig.json",
reportTypes: true,
includeEntryExports: true,
reportRedundancy: true,
semantic: { enabled: true },
});| Option | Type | Default | Description |
|---|---|---|---|
rootDir |
string |
required | Project root directory |
entryPatterns |
string[] |
auto-detected | Entry point glob patterns |
ignorePatterns |
string[] |
[] |
Glob patterns to exclude from analysis |
includeExtensions |
string[] |
[".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cjs", ".cts"] |
File extensions to scan |
tsConfigPath |
string | undefined |
undefined |
Path to tsconfig.json for path alias resolution |
reportTypes |
boolean |
false |
Include type-only exports in unusedExports |
includeEntryExports |
boolean |
false |
Report unused exports from entry files |
reportRedundancy |
boolean |
true |
Emit the redundancy / DRY findings listed above |
semantic |
SemanticConfig |
undefined |
Opt-in TypeScript type-aware analysis (see below) |
Off by default. Enable when you have typescript installed and a valid tsconfig.json:
const config = defineConfig({
rootDir: "./my-project",
semantic: {
enabled: true,
reportUnusedTypes: true,
reportUnusedEnumMembers: true,
reportUnusedClassMembers: false, // off by default, noisy on framework code
reportMisclassifiedDependencies: true,
reportRedundantVariableAliases: true,
reportRoundTripAliases: true,
},
});| Option | Default | Notes |
|---|---|---|
enabled |
false |
Master switch; semantic analysis loads the TS program and adds ~1–3s per scan |
reportUnusedTypes |
true |
Type aliases / interfaces / type-only exports never referenced |
reportUnusedEnumMembers |
true |
Enum members no reference site reads or writes |
reportUnusedClassMembers |
false |
Subclass overrides, framework method-by-name invocation (@HttpGet, lifecycle hooks) produce too many stylistic FPs to enable by default. Opt in selectively. |
reportMisclassifiedDependencies |
true |
dependencies packages used only via import type |
reportRedundantVariableAliases |
true |
Local aliases like const X = Y; export { X } |
reportRoundTripAliases |
true |
import { X as Y } from "./a"; export { Y as X } |
Every redundancy / semantic finding carries confidence: "high" | "medium" | "low". Use "high" for CI gates; "medium" and "low" are best treated as code-review prompts since intent is sometimes unknowable from syntax alone (e.g. ?? null may be required by a typed callback signature).
analyze() never throws on a corrupted file, unparseable tsconfig, or missing dependency. Failures surface as analysisErrors: DeslopError[] with structured code, module, severity, and path fields. See errors.ts for the full taxonomy. Errors at severity: "info" (empty files, binary files, minified bundles skipped from redundancy analysis) are informational and do not indicate problems.
pnpm install
pnpm build
pnpm test
pnpm lint
pnpm formatMIT