depvitals 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -10
- package/dist/cli/index.js +13 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/parseCliArgs.d.ts +37 -0
- package/dist/cli/parseCliArgs.d.ts.map +1 -0
- package/dist/cli/parseCliArgs.js +85 -0
- package/dist/cli/parseCliArgs.js.map +1 -0
- package/dist/cli/runCli.d.ts +31 -13
- package/dist/cli/runCli.d.ts.map +1 -1
- package/dist/cli/runCli.js +76 -84
- package/dist/cli/runCli.js.map +1 -1
- package/dist/core/analyzeProject.d.ts +92 -0
- package/dist/core/analyzeProject.d.ts.map +1 -0
- package/dist/core/analyzeProject.js +175 -0
- package/dist/core/analyzeProject.js.map +1 -0
- package/dist/reporters/terminalReporter.d.ts +49 -0
- package/dist/reporters/terminalReporter.d.ts.map +1 -0
- package/dist/reporters/terminalReporter.js +98 -0
- package/dist/reporters/terminalReporter.js.map +1 -0
- package/dist/scanner/moduleSpecifiers.d.ts +60 -0
- package/dist/scanner/moduleSpecifiers.d.ts.map +1 -0
- package/dist/scanner/moduleSpecifiers.js +824 -0
- package/dist/scanner/moduleSpecifiers.js.map +1 -0
- package/dist/scanner/packageSpecifier.d.ts +45 -0
- package/dist/scanner/packageSpecifier.d.ts.map +1 -0
- package/dist/scanner/packageSpecifier.js +98 -0
- package/dist/scanner/packageSpecifier.js.map +1 -0
- package/dist/scanner/projectManifest.d.ts +72 -0
- package/dist/scanner/projectManifest.d.ts.map +1 -0
- package/dist/scanner/projectManifest.js +176 -0
- package/dist/scanner/projectManifest.js.map +1 -0
- package/dist/scanner/scriptUsage.d.ts +50 -0
- package/dist/scanner/scriptUsage.d.ts.map +1 -0
- package/dist/scanner/scriptUsage.js +461 -0
- package/dist/scanner/scriptUsage.js.map +1 -0
- package/dist/scanner/sourceFiles.d.ts +52 -0
- package/dist/scanner/sourceFiles.d.ts.map +1 -0
- package/dist/scanner/sourceFiles.js +190 -0
- package/dist/scanner/sourceFiles.js.map +1 -0
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -2,28 +2,85 @@
|
|
|
2
2
|
|
|
3
3
|
> A simple, lightweight dependency health checker for Node.js projects.
|
|
4
4
|
|
|
5
|
-
DepVitals
|
|
5
|
+
DepVitals scans a Node.js project to identify declared dependencies that appear unused and imported packages that are not declared in `package.json`.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
focused alternative for checking project dependencies, without becoming a large all-in-one analysis
|
|
9
|
-
tool.
|
|
7
|
+
Inspired by [depcheck](https://github.com/depcheck/depcheck), DepVitals stays deliberately small. It performs lightweight static analysis locally, without making network requests, modifying the analyzed project, or executing its code.
|
|
10
8
|
|
|
11
9
|
## Usage
|
|
12
10
|
|
|
13
|
-
The `v0.0.1` CLI supports:
|
|
14
|
-
|
|
15
11
|
```bash
|
|
16
12
|
npx depvitals
|
|
13
|
+
npx depvitals ./path/to/project
|
|
17
14
|
npx depvitals --help
|
|
18
15
|
npx depvitals --version
|
|
19
16
|
```
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
Run it from a project directory to scan the current directory, or provide a path to analyze another project.
|
|
19
|
+
|
|
20
|
+
**Requirements:** Node.js `>=22.13.0`.
|
|
21
|
+
|
|
22
|
+
**Version note:** Dependency scanning was introduced in v0.1.0. The earlier v0.0.1 release contains only the initial CLI bootstrap.
|
|
23
|
+
|
|
24
|
+
**Exit status:**
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
0 = successful clean scan, help, or version
|
|
28
|
+
1 = dependency findings or an operational/CLI error
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Scan results, including dependency findings, are printed to `stdout`. Argument errors and operational errors are printed to `stderr`.
|
|
32
|
+
|
|
33
|
+
## What it detects
|
|
34
|
+
|
|
35
|
+
- **Unused dependencies** — packages declared in `dependencies` for which no supported source file or `package.json` script provides usage evidence.
|
|
36
|
+
- **Unused devDependencies** — the same analysis applied to packages declared in `devDependencies`.
|
|
37
|
+
- **Missing dependencies** — external packages referenced by supported source imports but not declared in the project's `package.json`.
|
|
38
|
+
|
|
39
|
+
DepVitals does not inspect `node_modules`, so **"missing" means "not declared", not "not installed"**. An installed but undeclared package can still be reported as missing, and package installation state is never validated.
|
|
40
|
+
|
|
41
|
+
Similarly, a dependency is reported as unused only when no supported usage evidence is found. Indirect or unsupported usage may still exist.
|
|
42
|
+
|
|
43
|
+
`peerDependencies` and `optionalDependencies` are considered when checking whether imported packages are declared, but are never reported as unused.
|
|
44
|
+
|
|
45
|
+
**Example output:**
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
DepVitals
|
|
49
|
+
|
|
50
|
+
Unused dependencies (2)
|
|
51
|
+
dotenv
|
|
52
|
+
lodash
|
|
53
|
+
|
|
54
|
+
Unused devDependencies (1)
|
|
55
|
+
eslint
|
|
56
|
+
|
|
57
|
+
Missing dependencies (1)
|
|
58
|
+
zod
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Supported in v0.1.0
|
|
62
|
+
|
|
63
|
+
- **JavaScript and TypeScript:** `.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`, `.mts`, `.cts`, including `.d.ts`-style declaration files.
|
|
64
|
+
- **Static ESM imports and exports:** regular imports, side-effect imports, `import type`, and `export ... from`.
|
|
65
|
+
- **Literal dynamic imports:** expressions such as `import("express")`.
|
|
66
|
+
- **Literal CommonJS requires:** expressions such as `require("express")`.
|
|
67
|
+
- **Basic `package.json` script awareness:** a declared dependency invoked by a supported script command counts as used, for example `eslint` in `"lint": "eslint ."`. Script usage can prevent unused findings but does not generate missing-dependency findings.
|
|
68
|
+
- **Node.js builtins:** built-in modules, with or without the `node:` prefix, are excluded from missing-dependency findings.
|
|
69
|
+
- **Scoped packages and subpaths:** package specifiers are normalized to their package root. For example, `@scope/ui/button` counts as `@scope/ui`, and `lodash/chunk` counts as `lodash`.
|
|
70
|
+
- **Ignored directories:** generated and vendor trees are skipped, including `node_modules`, `dist`, `build`, `coverage`, `out`, `.next`, `.nuxt`, `.cache`, `.turbo`, and `.git`.
|
|
71
|
+
- **Deterministic output:** findings are grouped into sections in a fixed order, with package names sorted alphabetically within each section.
|
|
72
|
+
|
|
73
|
+
Detection uses a lightweight static lexical scanner rather than a full JavaScript/TypeScript parser. Comments, ordinary strings, template text, and regular expressions that merely resemble imports are not counted as dependency usage.
|
|
22
74
|
|
|
23
|
-
|
|
75
|
+
## Current limitations
|
|
24
76
|
|
|
25
|
-
- `
|
|
26
|
-
-
|
|
77
|
+
- **Single-project analysis:** only one `package.json` is analyzed. Workspaces, monorepos, and parent-manifest lookup are not supported.
|
|
78
|
+
- **No configuration-aware resolution:** framework-specific configurations, plugins, TypeScript `paths`, and bundler aliases are not resolved.
|
|
79
|
+
- **Static specifiers only:** non-literal dynamic `import()`, template-literal specifiers, `require.resolve()`, and property calls such as `obj.require()` are not recognized as usage evidence.
|
|
80
|
+
- **Limited script detection:** script usage relies on supported command patterns and exact package-name matching. Executable names that differ from their package names are not automatically mapped; for example, `tsc` does not mark `typescript` as used.
|
|
81
|
+
- **Fixed directory exclusions:** source discovery uses the built-in ignored-directory list above. `.gitignore` and custom ignore rules are not interpreted.
|
|
82
|
+
- **Conservative error handling:** unreadable source files or source content the lexical scanner cannot safely finish scanning, such as unterminated strings, comments, templates, or regular expressions, abort the scan rather than producing partial results.
|
|
83
|
+
- **No remediation features yet:** automatic fixes, custom configuration files, and per-dependency explanations are not available.
|
|
27
84
|
|
|
28
85
|
## License
|
|
29
86
|
|
package/dist/cli/index.js
CHANGED
|
@@ -2,19 +2,25 @@
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { runCli } from './runCli.js';
|
|
4
4
|
/**
|
|
5
|
-
* Thin executable adapter for the `v0.0
|
|
5
|
+
* Thin executable adapter for the `v0.1.0` CLI.
|
|
6
6
|
*
|
|
7
7
|
* Its only responsibilities are:
|
|
8
8
|
* 1. resolve the package version from the single source of truth (`package.json`);
|
|
9
|
-
* 2.
|
|
10
|
-
* 3.
|
|
11
|
-
* 4.
|
|
9
|
+
* 2. collect `process.argv`, `process.cwd()` and the version;
|
|
10
|
+
* 3. await the pure orchestration in `runCli`;
|
|
11
|
+
* 4. render the returned stdout/stderr;
|
|
12
|
+
* 5. assign `process.exitCode` (never call `process.exit()`).
|
|
12
13
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
14
|
+
* All argument handling, scanning orchestration and error mapping live in `runCli`, so this file
|
|
15
|
+
* only wires process I/O to that orchestration. The relative path works both from the TypeScript
|
|
16
|
+
* source (`src/cli/index.ts`) and from the built output (`dist/cli/index.js`), because both resolve
|
|
17
|
+
* to the repository root `package.json`.
|
|
15
18
|
*/
|
|
16
19
|
const version = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8'));
|
|
17
|
-
const result = runCli(process.argv.slice(2),
|
|
20
|
+
const result = await runCli(process.argv.slice(2), {
|
|
21
|
+
version: version.version,
|
|
22
|
+
cwd: process.cwd(),
|
|
23
|
+
});
|
|
18
24
|
if (result.stdout.length > 0) {
|
|
19
25
|
process.stdout.write(result.stdout);
|
|
20
26
|
}
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CACxB,YAAY,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC9C,CAAC;AAEzB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACjD,OAAO,EAAE,OAAO,CAAC,OAAO;IACxB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;CACnB,CAAC,CAAC;AAEH,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;IAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAED,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;IAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAED,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, deterministic argument parsing for the `v0.1.0` CLI.
|
|
3
|
+
*
|
|
4
|
+
* This module only validates the argument shape and resolves the selected project path. It never
|
|
5
|
+
* touches the filesystem, never calls the analyzer, and never accesses `process`, so the parsing
|
|
6
|
+
* rules are fully unit-testable without any I/O.
|
|
7
|
+
*
|
|
8
|
+
* The supported shapes are intentionally small:
|
|
9
|
+
* - no arguments -> scan the injected `cwd`
|
|
10
|
+
* - exactly one positional -> scan the resolved project directory
|
|
11
|
+
* - exactly one meta flag -> help or version (exit 0, no scan)
|
|
12
|
+
* - anything else -> a deterministic error message
|
|
13
|
+
*
|
|
14
|
+
* `--help`/`-h`/`--version`/`-v` must stay standalone: combining them with any other token, or
|
|
15
|
+
* combining them with each other, is rejected rather than given precedence.
|
|
16
|
+
*/
|
|
17
|
+
/** The command selected after parsing the arguments. */
|
|
18
|
+
export type ParsedCommand = {
|
|
19
|
+
kind: 'help';
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'version';
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'scan';
|
|
24
|
+
projectPath: string;
|
|
25
|
+
} | {
|
|
26
|
+
kind: 'error';
|
|
27
|
+
message: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Parse the raw arguments (already stripped of `node` and the script path) into a single command.
|
|
31
|
+
*
|
|
32
|
+
* @param args - The raw arguments after `node` and the script path.
|
|
33
|
+
* @param cwd - The current working directory used as the base for relative project paths and as
|
|
34
|
+
* the default project when no argument is supplied.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseCliArgs(args: readonly string[], cwd: string): ParsedCommand;
|
|
37
|
+
//# sourceMappingURL=parseCliArgs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseCliArgs.d.ts","sourceRoot":"","sources":["../../src/cli/parseCliArgs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,wDAAwD;AACxD,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAiBvC;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CA8ChF"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, deterministic argument parsing for the `v0.1.0` CLI.
|
|
3
|
+
*
|
|
4
|
+
* This module only validates the argument shape and resolves the selected project path. It never
|
|
5
|
+
* touches the filesystem, never calls the analyzer, and never accesses `process`, so the parsing
|
|
6
|
+
* rules are fully unit-testable without any I/O.
|
|
7
|
+
*
|
|
8
|
+
* The supported shapes are intentionally small:
|
|
9
|
+
* - no arguments -> scan the injected `cwd`
|
|
10
|
+
* - exactly one positional -> scan the resolved project directory
|
|
11
|
+
* - exactly one meta flag -> help or version (exit 0, no scan)
|
|
12
|
+
* - anything else -> a deterministic error message
|
|
13
|
+
*
|
|
14
|
+
* `--help`/`-h`/`--version`/`-v` must stay standalone: combining them with any other token, or
|
|
15
|
+
* combining them with each other, is rejected rather than given precedence.
|
|
16
|
+
*/
|
|
17
|
+
import { resolve } from 'node:path';
|
|
18
|
+
/** Help/version flags that must be used alone. */
|
|
19
|
+
const HELP_FLAGS = new Set(['--help', '-h']);
|
|
20
|
+
/** Version flags that must be used alone. */
|
|
21
|
+
const VERSION_FLAGS = new Set(['--version', '-v']);
|
|
22
|
+
/** Hint appended to every argument error, so a failing run always points back to `--help`. */
|
|
23
|
+
const HINT = "Run 'depvitals --help' for available commands.";
|
|
24
|
+
/** Error returned when an empty string is passed as the project path. */
|
|
25
|
+
const INVALID_EMPTY_PROJECT_PATH = 'Invalid project path: project path must not be empty.\n' + HINT;
|
|
26
|
+
/** Error returned when more than one positional path is supplied. */
|
|
27
|
+
const TOO_MANY_ARGUMENTS = 'Too many arguments: expected at most one project path.\n' + HINT;
|
|
28
|
+
/**
|
|
29
|
+
* Parse the raw arguments (already stripped of `node` and the script path) into a single command.
|
|
30
|
+
*
|
|
31
|
+
* @param args - The raw arguments after `node` and the script path.
|
|
32
|
+
* @param cwd - The current working directory used as the base for relative project paths and as
|
|
33
|
+
* the default project when no argument is supplied.
|
|
34
|
+
*/
|
|
35
|
+
export function parseCliArgs(args, cwd) {
|
|
36
|
+
if (args.length === 0) {
|
|
37
|
+
return { kind: 'scan', projectPath: cwd };
|
|
38
|
+
}
|
|
39
|
+
if (args.length === 1) {
|
|
40
|
+
const arg = args[0];
|
|
41
|
+
// An empty string (or the unreachable undefined) is an explicit, invalid positional: it must
|
|
42
|
+
// not silently become `cwd`.
|
|
43
|
+
if (arg === undefined || arg === '') {
|
|
44
|
+
return { kind: 'error', message: INVALID_EMPTY_PROJECT_PATH };
|
|
45
|
+
}
|
|
46
|
+
if (HELP_FLAGS.has(arg)) {
|
|
47
|
+
return { kind: 'help' };
|
|
48
|
+
}
|
|
49
|
+
if (VERSION_FLAGS.has(arg)) {
|
|
50
|
+
return { kind: 'version' };
|
|
51
|
+
}
|
|
52
|
+
// Anything else that is not an option is treated as a project path.
|
|
53
|
+
if (!arg.startsWith('-')) {
|
|
54
|
+
return { kind: 'scan', projectPath: resolve(cwd, arg) };
|
|
55
|
+
}
|
|
56
|
+
return { kind: 'error', message: unknownOptionMessage(arg) };
|
|
57
|
+
}
|
|
58
|
+
// Two or more tokens: help/version must remain standalone, so any meta flag combined with
|
|
59
|
+
// additional tokens (including other meta flags) is rejected as used alone.
|
|
60
|
+
const metaFlag = args.find((arg) => HELP_FLAGS.has(arg) || VERSION_FLAGS.has(arg));
|
|
61
|
+
if (metaFlag !== undefined) {
|
|
62
|
+
return { kind: 'error', message: metaFlagMustBeUsedAlone(metaFlag) };
|
|
63
|
+
}
|
|
64
|
+
// No meta flag: reject unknown options before falling back to the positional rule, so an unknown
|
|
65
|
+
// flag is reported even when it appears alongside a positional path.
|
|
66
|
+
const unknownOption = args.find((arg) => arg.startsWith('-'));
|
|
67
|
+
if (unknownOption !== undefined) {
|
|
68
|
+
return { kind: 'error', message: unknownOptionMessage(unknownOption) };
|
|
69
|
+
}
|
|
70
|
+
// Remaining tokens are all positionals, which is more than one.
|
|
71
|
+
return { kind: 'error', message: TOO_MANY_ARGUMENTS };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The error message for an unrecognized option.
|
|
75
|
+
*/
|
|
76
|
+
function unknownOptionMessage(option) {
|
|
77
|
+
return `Unknown option: ${option}\n${HINT}`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The error message when a meta flag is combined with additional tokens.
|
|
81
|
+
*/
|
|
82
|
+
function metaFlagMustBeUsedAlone(flag) {
|
|
83
|
+
return `Option ${flag} must be used alone.\n${HINT}`;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=parseCliArgs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseCliArgs.js","sourceRoot":"","sources":["../../src/cli/parseCliArgs.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/runCli.d.ts
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Asynchronous CLI orchestration for `v0.1.0`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* `runCli` turns parsed arguments into a plain {@link CliResult}. It performs no process I/O of its
|
|
5
|
+
* own: it never writes to stdout/stderr and never touches `process`. The thin adapter in
|
|
6
|
+
* `index.ts` is the only code that renders the result.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
* -
|
|
8
|
+
* The responsibilities here are:
|
|
9
|
+
* - delegate argument validation to the pure {@link parseCliArgs};
|
|
10
|
+
* - run the static dependency scan with `analyzeProject`;
|
|
11
|
+
* - render the report with the pure terminal reporter;
|
|
12
|
+
* - decide the scan exit code from `hasDependencyIssues`, not from the report string;
|
|
13
|
+
* - convert operational failures into a concise CLI error result.
|
|
14
|
+
*
|
|
15
|
+
* It deliberately does not implement any scanning or dependency-analysis logic: that stays in
|
|
16
|
+
* `src/core`, and the reporter stays in `src/reporters`.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* The rendered CLI result: an exit code and the text to write to each stream. Exactly one of
|
|
20
|
+
* stdout/stderr is non-empty for every command, so a successful scan never mixes a report with an
|
|
21
|
+
* error and a failure never prints a misleading clean report.
|
|
13
22
|
*/
|
|
14
23
|
export type CliResult = {
|
|
15
24
|
exitCode: number;
|
|
@@ -17,10 +26,19 @@ export type CliResult = {
|
|
|
17
26
|
stderr: string;
|
|
18
27
|
};
|
|
19
28
|
/**
|
|
20
|
-
*
|
|
29
|
+
* Options supplied by the process adapter. Injecting `cwd` (rather than reading `process.cwd()`)
|
|
30
|
+
* keeps the orchestration pure and fully testable without mutating the working directory.
|
|
31
|
+
*/
|
|
32
|
+
export type CliOptions = {
|
|
33
|
+
version: string;
|
|
34
|
+
cwd: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Orchestrate the CLI for the given arguments.
|
|
21
38
|
*
|
|
22
|
-
* @param args - The raw arguments
|
|
23
|
-
* @param
|
|
39
|
+
* @param args - The raw arguments after `node` and the script path.
|
|
40
|
+
* @param options - The package version and the current working directory.
|
|
41
|
+
* @returns The exit code and the stdout/stderr text to render.
|
|
24
42
|
*/
|
|
25
|
-
export declare function runCli(args: readonly string[],
|
|
43
|
+
export declare function runCli(args: readonly string[], options: CliOptions): Promise<CliResult>;
|
|
26
44
|
//# sourceMappingURL=runCli.d.ts.map
|
package/dist/cli/runCli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runCli.d.ts","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"runCli.d.ts","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAkBF;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAa7F"}
|
package/dist/cli/runCli.js
CHANGED
|
@@ -1,111 +1,103 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Asynchronous CLI orchestration for `v0.1.0`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* `runCli` turns parsed arguments into a plain {@link CliResult}. It performs no process I/O of its
|
|
5
|
+
* own: it never writes to stdout/stderr and never touches `process`. The thin adapter in
|
|
6
|
+
* `index.ts` is the only code that renders the result.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
* -
|
|
8
|
+
* The responsibilities here are:
|
|
9
|
+
* - delegate argument validation to the pure {@link parseCliArgs};
|
|
10
|
+
* - run the static dependency scan with `analyzeProject`;
|
|
11
|
+
* - render the report with the pure terminal reporter;
|
|
12
|
+
* - decide the scan exit code from `hasDependencyIssues`, not from the report string;
|
|
13
|
+
* - convert operational failures into a concise CLI error result.
|
|
14
|
+
*
|
|
15
|
+
* It deliberately does not implement any scanning or dependency-analysis logic: that stays in
|
|
16
|
+
* `src/core`, and the reporter stays in `src/reporters`.
|
|
13
17
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
'Early development release.',
|
|
20
|
-
'Run `depvitals --help` for available commands.',
|
|
21
|
-
].join('\n');
|
|
18
|
+
import { AnalysisError, analyzeProject } from '../core/analyzeProject.js';
|
|
19
|
+
import { formatTerminalReport, hasDependencyIssues } from '../reporters/terminalReporter.js';
|
|
20
|
+
import { ProjectManifestError } from '../scanner/projectManifest.js';
|
|
21
|
+
import { SourceFilesError } from '../scanner/sourceFiles.js';
|
|
22
|
+
import { parseCliArgs } from './parseCliArgs.js';
|
|
22
23
|
const HELP_MESSAGE = [
|
|
23
24
|
'DepVitals',
|
|
24
25
|
'',
|
|
25
26
|
'A simple, lightweight dependency health checker for Node.js projects.',
|
|
26
27
|
'',
|
|
27
28
|
'Usage:',
|
|
28
|
-
' depvitals [
|
|
29
|
+
' depvitals [project]',
|
|
30
|
+
'',
|
|
31
|
+
'Arguments:',
|
|
32
|
+
' project Project directory to analyze (default: current directory)',
|
|
29
33
|
'',
|
|
30
34
|
'Options:',
|
|
31
|
-
' -h, --help
|
|
32
|
-
' -v, --version
|
|
35
|
+
' -h, --help Show help',
|
|
36
|
+
' -v, --version Show version',
|
|
33
37
|
].join('\n');
|
|
34
|
-
const PRODUCT_NAME = 'depvitals';
|
|
35
|
-
/**
|
|
36
|
-
* Render the early-development message shown when no argument is provided.
|
|
37
|
-
*/
|
|
38
|
-
function renderEarlyDevelopment() {
|
|
39
|
-
return {
|
|
40
|
-
exitCode: 0,
|
|
41
|
-
stdout: `${EARLY_DEVELOPMENT_MESSAGE}\n`,
|
|
42
|
-
stderr: '',
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Render the help output.
|
|
47
|
-
*/
|
|
48
|
-
function renderHelp() {
|
|
49
|
-
return {
|
|
50
|
-
exitCode: 0,
|
|
51
|
-
stdout: `${HELP_MESSAGE}\n`,
|
|
52
|
-
stderr: '',
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Render the package version. The version is passed in so the source of truth stays in
|
|
57
|
-
* `package.json` and is never duplicated as a hard-coded constant.
|
|
58
|
-
*/
|
|
59
|
-
function renderVersion(version) {
|
|
60
|
-
return {
|
|
61
|
-
exitCode: 0,
|
|
62
|
-
stdout: `${version}\n`,
|
|
63
|
-
stderr: '',
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
38
|
/**
|
|
67
|
-
*
|
|
39
|
+
* Orchestrate the CLI for the given arguments.
|
|
40
|
+
*
|
|
41
|
+
* @param args - The raw arguments after `node` and the script path.
|
|
42
|
+
* @param options - The package version and the current working directory.
|
|
43
|
+
* @returns The exit code and the stdout/stderr text to render.
|
|
68
44
|
*/
|
|
69
|
-
function
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
45
|
+
export async function runCli(args, options) {
|
|
46
|
+
const command = parseCliArgs(args, options.cwd);
|
|
47
|
+
switch (command.kind) {
|
|
48
|
+
case 'help':
|
|
49
|
+
return { exitCode: 0, stdout: `${HELP_MESSAGE}\n`, stderr: '' };
|
|
50
|
+
case 'version':
|
|
51
|
+
return { exitCode: 0, stdout: `${options.version}\n`, stderr: '' };
|
|
52
|
+
case 'error':
|
|
53
|
+
return { exitCode: 1, stdout: '', stderr: `${command.message}\n` };
|
|
54
|
+
case 'scan':
|
|
55
|
+
return await runScan(command.projectPath);
|
|
56
|
+
}
|
|
79
57
|
}
|
|
80
58
|
/**
|
|
81
|
-
*
|
|
59
|
+
* Run the scan for a single project and render its report.
|
|
82
60
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
61
|
+
* Operational failures from the scanner are converted into a concise CLI error result (exit 1,
|
|
62
|
+
* empty stdout). Any other thrown value is surfaced through a generic fallback message so the CLI
|
|
63
|
+
* never leaks internal error objects and never leaves an unhandled rejection.
|
|
85
64
|
*/
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
65
|
+
async function runScan(projectPath) {
|
|
66
|
+
let result;
|
|
67
|
+
try {
|
|
68
|
+
result = await analyzeProject(projectPath);
|
|
89
69
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
case '-h':
|
|
94
|
-
return renderHelp();
|
|
95
|
-
case '--version':
|
|
96
|
-
case '-v':
|
|
97
|
-
return renderVersion(version);
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (isOperationalError(error)) {
|
|
72
|
+
return { exitCode: 1, stdout: '', stderr: `${error.message}\n` };
|
|
98
73
|
}
|
|
74
|
+
return {
|
|
75
|
+
exitCode: 1,
|
|
76
|
+
stdout: '',
|
|
77
|
+
stderr: `${unexpectedErrorMessage(projectPath, error)}\n`,
|
|
78
|
+
};
|
|
99
79
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const firstUnknown = args.find((argument) => !isKnownFlag(argument));
|
|
103
|
-
return renderUnknownOption(firstUnknown ?? args.join(' '));
|
|
80
|
+
const hasIssues = hasDependencyIssues(result);
|
|
81
|
+
return { exitCode: hasIssues ? 1 : 0, stdout: formatTerminalReport(result), stderr: '' };
|
|
104
82
|
}
|
|
105
83
|
/**
|
|
106
|
-
* Whether
|
|
84
|
+
* Whether the thrown value is a scanner error the CLI knows how to render. Only the existing typed
|
|
85
|
+
* error classes count; everything else is treated as an unexpected internal failure.
|
|
107
86
|
*/
|
|
108
|
-
function
|
|
109
|
-
return (
|
|
87
|
+
function isOperationalError(error) {
|
|
88
|
+
return (error instanceof ProjectManifestError ||
|
|
89
|
+
error instanceof SourceFilesError ||
|
|
90
|
+
error instanceof AnalysisError);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The fallback message for an unexpected thrown value. The path is always included so the failure
|
|
94
|
+
* is traceable; the underlying message is only appended when it is a non-empty, useful `Error`
|
|
95
|
+
* message, so unknown throwables never leak serialized internals.
|
|
96
|
+
*/
|
|
97
|
+
function unexpectedErrorMessage(projectPath, error) {
|
|
98
|
+
if (error instanceof Error && error.message.trim().length > 0) {
|
|
99
|
+
return `Unexpected error while analyzing project ${projectPath}: ${error.message}`;
|
|
100
|
+
}
|
|
101
|
+
return `Unexpected error while analyzing project ${projectPath}.`;
|
|
110
102
|
}
|
|
111
103
|
//# sourceMappingURL=runCli.js.map
|
package/dist/cli/runCli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runCli.js","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"runCli.js","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency analysis.
|
|
3
|
+
*
|
|
4
|
+
* This module combines the outputs of the manifest loader, source discovery, module-specifier
|
|
5
|
+
* extraction, package-specifier classification and script-usage detection into the first real
|
|
6
|
+
* dependency-analysis engine.
|
|
7
|
+
*
|
|
8
|
+
* It answers exactly three questions about a single Node.js project:
|
|
9
|
+
* - which `dependencies` are never referenced (neither by source files nor by `package.json`
|
|
10
|
+
* scripts)?
|
|
11
|
+
* - which `devDependencies` are never referenced?
|
|
12
|
+
* - which external packages are referenced by source files but are not declared anywhere?
|
|
13
|
+
*
|
|
14
|
+
* It deliberately does not:
|
|
15
|
+
* - decide whether a dependency is misplaced, a misconfigured peer/optional, or a scoped
|
|
16
|
+
* dependency (that belongs to later releases);
|
|
17
|
+
* - resolve specifiers against `node_modules`, `tsconfig` `paths`, `package.json#imports` or
|
|
18
|
+
* bundler aliases (Step 10 only classifies a raw specifier);
|
|
19
|
+
* - render terminal output, JSON, evidence or confidence (that belongs to later steps);
|
|
20
|
+
* - execute or import any analyzed source, run package scripts, or mutate the analyzed project;
|
|
21
|
+
* - consult the network or the npm registry.
|
|
22
|
+
*
|
|
23
|
+
* The pipeline is intentionally sequential and single-pass: each discovered source file is read
|
|
24
|
+
* once and parsed once. No concurrency pool, cache or index is introduced before a measured need
|
|
25
|
+
* appears.
|
|
26
|
+
*
|
|
27
|
+
* Usage/missing formulas (`usedNames` is the union of source-external package roots and script-used
|
|
28
|
+
* package names; `declaredDependencyNames` is the union of every declared dependency section):
|
|
29
|
+
*
|
|
30
|
+
* ```text
|
|
31
|
+
* sourceUsedNames = external package roots extracted from source files
|
|
32
|
+
* scriptUsedNames = findPackageScriptUsage(scripts, dependencies ∪ devDependencies)
|
|
33
|
+
* usedNames = sourceUsedNames ∪ scriptUsedNames
|
|
34
|
+
* unusedDependencies = dependencies − usedNames
|
|
35
|
+
* unusedDevDependencies = devDependencies − usedNames
|
|
36
|
+
* missingDependencies = sourceUsedNames − declaredDependencyNames
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* Scripts never generate missing-dependency findings, and peer/optional declarations suppress false
|
|
40
|
+
* missing results through `declaredDependencyNames`.
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* The structured outcome of a dependency analysis.
|
|
44
|
+
*
|
|
45
|
+
* Every package-name list is sorted alphabetically and contains no duplicates. The result carries
|
|
46
|
+
* only the facts needed by the `v0.1.0` report: the project root and the three unused/missing
|
|
47
|
+
* categories. Confidence, explanations, evidence, severity and JSON schema version are deliberately
|
|
48
|
+
* absent: they are future roadmap concepts.
|
|
49
|
+
*/
|
|
50
|
+
export type AnalysisResult = {
|
|
51
|
+
/** Absolute, normalized project root (from the manifest). */
|
|
52
|
+
projectRoot: string;
|
|
53
|
+
/** Unused `dependencies`, sorted alphabetically. */
|
|
54
|
+
unusedDependencies: readonly string[];
|
|
55
|
+
/** Unused `devDependencies`, sorted alphabetically. */
|
|
56
|
+
unusedDevDependencies: readonly string[];
|
|
57
|
+
/** External packages referenced by source but not declared anywhere, sorted alphabetically. */
|
|
58
|
+
missingDependencies: readonly string[];
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Why the analysis could not complete.
|
|
62
|
+
*
|
|
63
|
+
* - `unreadable-source`: a discovered source file could not be read from disk.
|
|
64
|
+
* - `invalid-source`: a discovered source file reached a lexical state from which the specifier
|
|
65
|
+
* extractor cannot safely continue (an unterminated string/comment/template/regex, or a malformed
|
|
66
|
+
* string escape).
|
|
67
|
+
*/
|
|
68
|
+
export type AnalysisErrorCode = 'unreadable-source' | 'invalid-source';
|
|
69
|
+
/**
|
|
70
|
+
* Operational error for the dependency-analysis engine.
|
|
71
|
+
*
|
|
72
|
+
* The `code` lets callers (the CLI in a later step) render a clean message without matching on error
|
|
73
|
+
* strings, and the preserved `cause` keeps the original filesystem or parsing failure. The affected
|
|
74
|
+
* source-file path is always included in the message so an unreadable or invalid file is never
|
|
75
|
+
* silently skipped.
|
|
76
|
+
*/
|
|
77
|
+
export declare class AnalysisError extends Error {
|
|
78
|
+
readonly code: AnalysisErrorCode;
|
|
79
|
+
constructor(message: string, code: AnalysisErrorCode, cause?: unknown);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Analyze the single project rooted at `projectRoot` and return the structured unused/missing result.
|
|
83
|
+
*
|
|
84
|
+
* The supplied root is resolved to an absolute path; `process.cwd()` is never changed and the target
|
|
85
|
+
* project is never written to.
|
|
86
|
+
*
|
|
87
|
+
* @throws {AnalysisError} when a discovered source file cannot be read or cannot be safely analyzed.
|
|
88
|
+
* @throws {ProjectManifestError} when the manifest is missing, unreadable, invalid or malformed.
|
|
89
|
+
* @throws {SourceFilesError} when the root is missing, is not a directory, or cannot be read.
|
|
90
|
+
*/
|
|
91
|
+
export declare function analyzeProject(projectRoot: string): Promise<AnalysisResult>;
|
|
92
|
+
//# sourceMappingURL=analyzeProject.d.ts.map
|