depvitals 0.2.0 → 0.4.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.
Files changed (89) hide show
  1. package/README.md +95 -30
  2. package/dist/cli/entry.js +8 -21
  3. package/dist/cli/entry.js.map +1 -1
  4. package/dist/cli/parseCliArgs.d.ts +5 -2
  5. package/dist/cli/parseCliArgs.d.ts.map +1 -1
  6. package/dist/cli/parseCliArgs.js +51 -36
  7. package/dist/cli/parseCliArgs.js.map +1 -1
  8. package/dist/cli/runCli.d.ts +4 -5
  9. package/dist/cli/runCli.d.ts.map +1 -1
  10. package/dist/cli/runCli.js +41 -46
  11. package/dist/cli/runCli.js.map +1 -1
  12. package/dist/config/ignoreDependencies.d.ts +9 -0
  13. package/dist/config/ignoreDependencies.d.ts.map +1 -0
  14. package/dist/config/ignoreDependencies.js +22 -0
  15. package/dist/config/ignoreDependencies.js.map +1 -0
  16. package/dist/config/ignorePaths.d.ts +13 -0
  17. package/dist/config/ignorePaths.d.ts.map +1 -0
  18. package/dist/config/ignorePaths.js +47 -0
  19. package/dist/config/ignorePaths.js.map +1 -0
  20. package/dist/config/projectConfigError.d.ts +7 -0
  21. package/dist/config/projectConfigError.d.ts.map +1 -0
  22. package/dist/config/projectConfigError.js +10 -0
  23. package/dist/config/projectConfigError.js.map +1 -0
  24. package/dist/config/readProjectConfig.d.ts +28 -0
  25. package/dist/config/readProjectConfig.d.ts.map +1 -0
  26. package/dist/config/readProjectConfig.js +120 -0
  27. package/dist/config/readProjectConfig.js.map +1 -0
  28. package/dist/core/analyzeProject.d.ts +40 -1
  29. package/dist/core/analyzeProject.d.ts.map +1 -1
  30. package/dist/core/analyzeProject.js +189 -45
  31. package/dist/core/analyzeProject.js.map +1 -1
  32. package/dist/core/evidence.d.ts +67 -0
  33. package/dist/core/evidence.d.ts.map +1 -0
  34. package/dist/core/evidence.js +115 -0
  35. package/dist/core/evidence.js.map +1 -0
  36. package/dist/core/scanContext.d.ts +20 -0
  37. package/dist/core/scanContext.d.ts.map +1 -0
  38. package/dist/core/scanContext.js +43 -0
  39. package/dist/core/scanContext.js.map +1 -0
  40. package/dist/detectors/eslintManifestConfig.d.ts +18 -0
  41. package/dist/detectors/eslintManifestConfig.d.ts.map +1 -1
  42. package/dist/detectors/eslintManifestConfig.js +62 -80
  43. package/dist/detectors/eslintManifestConfig.js.map +1 -1
  44. package/dist/detectors/eslintRcJsonConfig.d.ts +8 -2
  45. package/dist/detectors/eslintRcJsonConfig.d.ts.map +1 -1
  46. package/dist/detectors/eslintRcJsonConfig.js +27 -12
  47. package/dist/detectors/eslintRcJsonConfig.js.map +1 -1
  48. package/dist/detectors/jestManifestConfig.d.ts +15 -3
  49. package/dist/detectors/jestManifestConfig.d.ts.map +1 -1
  50. package/dist/detectors/jestManifestConfig.js +63 -83
  51. package/dist/detectors/jestManifestConfig.js.map +1 -1
  52. package/dist/reporters/jsonReporter.d.ts +39 -0
  53. package/dist/reporters/jsonReporter.d.ts.map +1 -0
  54. package/dist/reporters/jsonReporter.js +91 -0
  55. package/dist/reporters/jsonReporter.js.map +1 -0
  56. package/dist/reporters/terminalReporter.d.ts +15 -4
  57. package/dist/reporters/terminalReporter.d.ts.map +1 -1
  58. package/dist/reporters/terminalReporter.js +64 -4
  59. package/dist/reporters/terminalReporter.js.map +1 -1
  60. package/dist/scanner/moduleSpecifiers.d.ts +12 -2
  61. package/dist/scanner/moduleSpecifiers.d.ts.map +1 -1
  62. package/dist/scanner/moduleSpecifiers.js +1154 -183
  63. package/dist/scanner/moduleSpecifiers.js.map +1 -1
  64. package/dist/scanner/packageSpecifier.d.ts +26 -2
  65. package/dist/scanner/packageSpecifier.d.ts.map +1 -1
  66. package/dist/scanner/packageSpecifier.js +70 -2
  67. package/dist/scanner/packageSpecifier.js.map +1 -1
  68. package/dist/scanner/projectManifest.d.ts +28 -3
  69. package/dist/scanner/projectManifest.d.ts.map +1 -1
  70. package/dist/scanner/projectManifest.js +58 -13
  71. package/dist/scanner/projectManifest.js.map +1 -1
  72. package/dist/scanner/scriptUsage.d.ts +15 -1
  73. package/dist/scanner/scriptUsage.d.ts.map +1 -1
  74. package/dist/scanner/scriptUsage.js +284 -69
  75. package/dist/scanner/scriptUsage.js.map +1 -1
  76. package/dist/scanner/sourceFiles.d.ts +21 -2
  77. package/dist/scanner/sourceFiles.d.ts.map +1 -1
  78. package/dist/scanner/sourceFiles.js +19 -6
  79. package/dist/scanner/sourceFiles.js.map +1 -1
  80. package/package.json +4 -2
  81. package/schemas/README.md +47 -0
  82. package/schemas/examples/README.md +27 -0
  83. package/schemas/examples/explain-excluded.json +53 -0
  84. package/schemas/examples/explain-missing.json +65 -0
  85. package/schemas/examples/explain-node-preload.json +70 -0
  86. package/schemas/examples/explain-unknown.json +53 -0
  87. package/schemas/examples/scan-clean.json +40 -0
  88. package/schemas/examples/scan-findings.json +80 -0
  89. package/schemas/report-v1.schema.json +376 -0
package/README.md CHANGED
@@ -1,70 +1,135 @@
1
1
  # DepVitals
2
2
 
3
- DepVitals finds unused and undeclared npm dependencies in single-package JavaScript and TypeScript projects. It is a zero-config Node.js CLI with a custom static scanner and no runtime dependencies.
3
+ [![npm version](https://img.shields.io/npm/v/depvitals)](https://www.npmjs.com/package/depvitals)
4
+ [![Runtime dependencies: 0](https://img.shields.io/badge/runtime_dependencies-0-brightgreen)](https://github.com/MatiasRicardi/depvitals/blob/main/package.json)
5
+ [![CI](https://github.com/MatiasRicardi/depvitals/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/MatiasRicardi/depvitals/actions/workflows/ci.yml)
6
+ [![codecov](https://codecov.io/gh/MatiasRicardi/depvitals/graph/badge.svg?branch=main)](https://codecov.io/gh/MatiasRicardi/depvitals)
7
+ [![CodeQL](https://github.com/MatiasRicardi/depvitals/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/MatiasRicardi/depvitals/actions/workflows/codeql.yml)
8
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/MatiasRicardi/depvitals/blob/main/LICENSE)
4
9
 
5
- [Depcheck](https://github.com/depcheck/depcheck)-inspired, DepVitals focuses on dependency declarations and supported usage evidence. Use it to review dependencies during maintenance or before a release; review each finding before changing your manifest.
10
+ DepVitals is a lightweight, [Depcheck](https://github.com/depcheck/depcheck)-inspired **npm dependency analyzer for Node.js, JavaScript and TypeScript projects**. It finds **unused dependencies, unused devDependencies and missing (undeclared) dependencies** using a custom static scanner with **zero runtime dependencies**.
6
11
 
7
- Documentation on `main` can be ahead of the [published npm package](https://www.npmjs.com/package/depvitals). Check the [changelog](https://github.com/MatiasRicardi/depvitals/blob/main/CHANGELOG.md) for release-specific behavior.
12
+ Designed for fast, zero-config dependency checks during development, maintenance and CI, its CLI can also be used in scripts and AI coding-agent workflows. It analyzes one project root at a time; review findings before changing `package.json`.
13
+
14
+ ## What's new in v0.4.0
15
+
16
+ Export a versioned JSON report, explain why a package was used or flagged, and run a
17
+ [version-pinned CI check](#ci-with-a-fixed-version) that preserves reports and diagnostics.
18
+ Explanations point to supported source, script and configuration evidence. Supported explicit
19
+ Node preloads now count as script usage for declared packages. See the
20
+ [v0.4.0 release notes](https://github.com/MatiasRicardi/depvitals/blob/main/docs/releases/v0.4.0.md)
21
+ for compatibility details and remaining limits.
8
22
 
9
23
  ## Quick start
10
24
 
11
- Requires **Node.js 22.13.0 or newer**. From a directory containing `package.json`:
25
+ Requires **Node.js 22.13.0 or newer**. Scan the current directory containing `package.json`, or pass a project path:
12
26
 
13
27
  ```sh
14
28
  npx depvitals
29
+ npx depvitals ./path/to/project
15
30
  ```
16
31
 
17
- Scan an explicit project path, or request standalone help/version:
32
+ ### Install globally
18
33
 
19
34
  ```sh
20
- npx depvitals ./path/to/project
21
- npx depvitals --help
22
- npx depvitals --version
35
+ npm i -g depvitals
36
+ depvitals
37
+ depvitals ./path/to/project
23
38
  ```
24
39
 
25
- These commands run the npm release. For development-branch behavior, build and run the local CLI as described in [Contributing](https://github.com/MatiasRicardi/depvitals/blob/main/CONTRIBUTING.md).
40
+ Use `depvitals --help` or `depvitals --version` for standalone help/version; the same flags work with `npx depvitals`.
41
+
42
+ These commands use the npm release. Documentation on `main` can describe unreleased changes; see the [changelog](https://github.com/MatiasRicardi/depvitals/blob/main/CHANGELOG.md). To try the development checkout, [build and run the local CLI](https://github.com/MatiasRicardi/depvitals/blob/main/CONTRIBUTING.md#local-setup).
43
+
44
+ ## Results
26
45
 
27
- ## Understand the results
46
+ | Finding | Meaning |
47
+ | ---------------------- | -------------------------------------------------------------------------------------- |
48
+ | Unused dependencies | Declared in `dependencies`, without supported usage evidence. |
49
+ | Unused devDependencies | The same check for `devDependencies`. |
50
+ | Missing dependencies | Referenced by supported source imports/exports/requires, but undeclared in all groups. |
28
51
 
29
- | Finding | Meaning |
30
- | ---------------------- | ------------------------------------------------------------------------------------------------------------ |
31
- | Unused dependencies | Entries in `dependencies` with no supported source, script or configuration usage evidence. |
32
- | Unused devDependencies | The same check for `devDependencies`. |
33
- | Missing dependencies | Packages referenced by supported source imports/requires but absent from every dependency declaration group. |
52
+ **Missing means undeclared.** DepVitals checks the manifest and supported evidence. Review each unused finding before editing your manifest. Peer and optional dependencies suppress missing findings and are never reported unused.
34
53
 
35
- **Missing means undeclared, not uninstalled.** DepVitals does not inspect `node_modules`. **Unused is not proof of safe removal**: indirect or unsupported usage may exist. Peer and optional declarations suppress missing findings and are never reported as unused.
54
+ Reports use stdout; operational errors use stderr without a partial report. Exit **0** means clean/help/version; **1** means findings/errors. An optional update notice can use stderr without changing the status.
36
55
 
37
- A scan can report:
56
+ ## JSON reports and package explanations
57
+
58
+ These examples require **v0.4.0 or newer**. To try them from a checkout, use
59
+ `node /path/to/depvitals/dist/cli/index.js` in place of `depvitals` after
60
+ [building the development checkout](https://github.com/MatiasRicardi/depvitals/blob/main/CONTRIBUTING.md#local-setup).
61
+
62
+ For example, suppose `./project` declares `unused` as a dependency and `unused-tool` as a
63
+ devDependency, and `src/index.ts` contains `import item from 'missing';`.
64
+
65
+ ```sh
66
+ depvitals ./project
67
+ ```
38
68
 
39
69
  ```text
40
70
  DepVitals
41
71
 
42
72
  Unused dependencies (1)
43
- lodash
73
+ unused
44
74
 
45
75
  Unused devDependencies (1)
46
- echo-only
76
+ unused-tool
47
77
 
48
78
  Missing dependencies (1)
49
- undeclared-pkg
79
+ missing
50
80
  ```
51
81
 
52
- Reports go to stdout; operational errors go to stderr. Exit status is **0** for a clean scan, help or version, and **1** for findings or errors. An eligible update notice may additionally use stderr without changing the status.
82
+ Run these commands from outside the selected project.
53
83
 
54
- ## Coverage and fit
84
+ ```sh
85
+ depvitals ./project --format json > depvitals-report.json
86
+ depvitals ./project --explain missing
87
+ depvitals --format json --explain missing ./project
88
+ ```
89
+
90
+ 1. Start with a full scan. This example reports findings and returns exit 1, including when stdout
91
+ is redirected to JSON.
92
+ 2. Explain the package and check its evidence. Here `missing` is undeclared and its explanation
93
+ points to the import in `src/index.ts:1:18`. Check which package owns the file and whether the
94
+ import belongs in that project.
95
+ 3. For an unused finding, review actual uses and test the project before changing the manifest.
96
+ Use an exclusion only to record a deliberate scope or reporting decision.
55
97
 
56
- DepVitals recognizes literal ESM/CommonJS imports, exports and requires in JavaScript, TypeScript, JSX/TSX and declaration files. It normalizes scoped/subpath imports and excludes Node builtins and internal paths.
98
+ An explanation reports one exact package. Its exit status follows that package's result. Use a full
99
+ scan to enforce a project-wide check. The v0.4.0 [report schema and examples](https://github.com/MatiasRicardi/depvitals/blob/main/schemas/README.md)
100
+ are shipped in the npm package under `schemas/`. See the [CLI and report contract](https://github.com/MatiasRicardi/depvitals/blob/main/docs/reference.md#cli-and-json-reports).
57
101
 
58
- Supported `package.json` commands and bounded ESLint/Jest configuration hints can prevent unused findings for declared packages. Only source evidence creates missing findings. See the [technical reference](https://github.com/MatiasRicardi/depvitals/blob/main/docs/reference.md) for supported patterns, precedence and exclusions.
102
+ ## CI with a fixed version
59
103
 
60
- ## Limits and update check
104
+ Install v0.4.0 from npm as an exact development dependency. If you are testing a candidate before
105
+ publication, use the local tarball procedure in the CI recipe below.
106
+
107
+ ```sh
108
+ npm install --save-dev --save-exact depvitals@0.4.0
109
+ ```
110
+
111
+ Commit the generated lockfile and use `"check:dependencies": "depvitals --format json"` in the
112
+ manifest's `scripts`. The [tested CI recipe](https://github.com/MatiasRicardi/depvitals/blob/main/docs/examples/ci/README.md)
113
+ captures the installed executable's report, diagnostics and status. It preserves those artifacts
114
+ on failure.
115
+
116
+ ## Optional configuration
117
+
118
+ Requires DepVitals **0.3.0 or newer**. Create `depvitals.config.json` at the scanned project root:
119
+
120
+ ```json
121
+ {
122
+ "ignorePaths": ["examples", "src/generated"],
123
+ "ignoreDependencies": ["some-adapter"]
124
+ }
125
+ ```
61
126
 
62
- Analysis covers one project root, without workspace aggregation, alias/tsconfig resolution or blanket `@types` inference. The scanner is not a full compiler or resolver. Dynamic references can be missed; generated/vendor directories are excluded using fixed rules. There is no JSON output, public analyzer API, per-package explanation or automatic fix.
127
+ `ignorePaths` excludes literal source paths/subtrees; `ignoreDependencies` hides exact package names from findings. No globs. Exclusions narrow what a clean report means; excluding the only source reference can make a dependency unused. See the [configuration reference](https://github.com/MatiasRicardi/depvitals/blob/main/docs/reference.md#optional-project-configuration) for validation and precedence.
63
128
 
64
- Core analysis is offline and never executes or modifies the analyzed project. After a completed interactive scan, an optional, bounded update check can request public metadata for **DepVitals itself** and cache it outside the project for about 24 hours. It uploads no source or dependency list and adds no telemetry. CI, non-TTY, help/version and failed scans skip the check. Set `DEPVITALS_NO_UPDATE_CHECK=1` to disable it; the [reference](https://github.com/MatiasRicardi/depvitals/blob/main/docs/reference.md#update-notice-and-privacy) shows POSIX and PowerShell examples.
129
+ ## Scope and privacy
65
130
 
66
- ## More
131
+ Scans cover JS/TS, JSX/TSX and declaration files, literal ESM/CommonJS references, supported script commands and bounded ESLint/Jest hints. Only source evidence creates missing findings. There is no workspace aggregation, alias/tsconfig resolution, blanket `@types` inference or automatic fix; see [supported patterns and limits](https://github.com/MatiasRicardi/depvitals/blob/main/docs/reference.md).
67
132
 
68
- [Technical reference](https://github.com/MatiasRicardi/depvitals/blob/main/docs/reference.md) · [Contributing](https://github.com/MatiasRicardi/depvitals/blob/main/CONTRIBUTING.md) · [Changelog](https://github.com/MatiasRicardi/depvitals/blob/main/CHANGELOG.md) · [npm](https://www.npmjs.com/package/depvitals) · [Repository](https://github.com/MatiasRicardi/depvitals)
133
+ Core analysis is offline and never executes or modifies the project or inspects `node_modules`. After completed interactive scans, an optional update check requests public metadata for **DepVitals itself**, caches it outside the project and uploads no project data. CI, non-TTY, help/version and failed scans skip it. In v0.4.0, JSON scans and all explanations also skip it before any cache or network access. Set `DEPVITALS_NO_UPDATE_CHECK=1` to disable it; see [privacy and shell examples](https://github.com/MatiasRicardi/depvitals/blob/main/docs/reference.md#update-notice-and-privacy).
69
134
 
70
- [MIT license](https://github.com/MatiasRicardi/depvitals/blob/main/LICENSE).
135
+ [Technical reference](https://github.com/MatiasRicardi/depvitals/blob/main/docs/reference.md) · [Contributing](https://github.com/MatiasRicardi/depvitals/blob/main/CONTRIBUTING.md) · [Changelog](https://github.com/MatiasRicardi/depvitals/blob/main/CHANGELOG.md) · [MIT license](https://github.com/MatiasRicardi/depvitals/blob/main/LICENSE)
package/dist/cli/entry.js CHANGED
@@ -56,10 +56,17 @@ export async function runCliEntry(args, options) {
56
56
  * stand on their own. An unexpected type is discarded rather than printed.
57
57
  */
58
58
  async function collectNotice(args, result, options) {
59
+ const command = parseCliArgs(args, options.cwd);
60
+ if (command.kind !== 'scan' ||
61
+ command.format === 'json' ||
62
+ command.explain !== undefined ||
63
+ result.stdout.length === 0 ||
64
+ result.stderr.length > 0)
65
+ return undefined;
59
66
  try {
60
67
  const collect = options.updateNotice ?? collectUpdateNotice;
61
68
  const notice = await collect({
62
- commandKind: commandKindOf(args, options.cwd, result),
69
+ commandKind: 'scan',
63
70
  currentVersion: options.version,
64
71
  env: options.env,
65
72
  stdoutTTY: options.stdout.isTTY === true,
@@ -72,24 +79,4 @@ async function collectNotice(args, result, options) {
72
79
  return undefined;
73
80
  }
74
81
  }
75
- /**
76
- * Classify the invocation in the vocabulary the eligibility predicate expects.
77
- *
78
- * The argument parser is the single source of truth for `help`, `version` and usage errors, so it is
79
- * consulted again here (a pure, deterministic function of the same arguments and the same working
80
- * directory) instead of widening {@link CliResult}, whose three keys are pinned by the contract gate.
81
- * A parsed `scan` is then split by what the scan produced: {@link runCli} renders a report whenever
82
- * the scan completed - clean or with findings - and leaves stdout empty for an operational failure,
83
- * so an empty report means the scan never finished and nothing may be suggested to the user.
84
- *
85
- * Only the literal kind crosses the boundary; the parsed project path stays here and is never passed
86
- * into notifier code.
87
- */
88
- function commandKindOf(args, cwd, result) {
89
- const command = parseCliArgs(args, cwd);
90
- if (command.kind !== 'scan') {
91
- return command.kind;
92
- }
93
- return result.stdout.length === 0 ? 'scan-failure' : 'scan';
94
- }
95
82
  //# sourceMappingURL=entry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../src/cli/entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EACL,mBAAmB,GAGpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAmC,MAAM,EAAE,MAAM,aAAa,CAAC;AA2BtE;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAuB,EACvB,OAAwB;IAExB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAElF,sEAAsE;IACtE,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAE1D,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,aAAa,CAC1B,IAAuB,EACvB,MAAiB,EACjB,OAAwB;IAExB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,IAAI,mBAAmB,CAAC;QAE5D,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC;YAC3B,WAAW,EAAE,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC;YACrD,cAAc,EAAE,OAAO,CAAC,OAAO;YAC/B,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;YACxC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;SACzC,CAAC,CAAC;QAEH,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;QAC/D,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAS,aAAa,CACpB,IAAuB,EACvB,GAAW,EACX,MAAiB;IAEjB,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAExC,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,OAAO,CAAC,IAAI,CAAC;IACtB,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC;AAC9D,CAAC"}
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../src/cli/entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EACL,mBAAmB,GAGpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAmC,MAAM,EAAE,MAAM,aAAa,CAAC;AA2BtE;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAuB,EACvB,OAAwB;IAExB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAElF,sEAAsE;IACtE,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAE1D,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,aAAa,CAC1B,IAAuB,EACvB,MAAiB,EACjB,OAAwB;IAExB,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAChD,IACE,OAAO,CAAC,IAAI,KAAK,MAAM;QACvB,OAAO,CAAC,MAAM,KAAK,MAAM;QACzB,OAAO,CAAC,OAAO,KAAK,SAAS;QAC7B,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;QAC1B,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAExB,OAAO,SAAS,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,IAAI,mBAAmB,CAAC;QAE5D,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC;YAC3B,WAAW,EAAE,MAAM;YACnB,cAAc,EAAE,OAAO,CAAC,OAAO;YAC/B,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;YACxC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;SACzC,CAAC,CAAC;QAEH,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;QAC/D,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Pure, deterministic argument parsing for the `v0.1.0` CLI.
2
+ * Pure, deterministic CLI argument parsing.
3
3
  *
4
4
  * This module only validates the argument shape and resolves the selected project path. It never
5
5
  * touches the filesystem, never calls the analyzer, and never accesses `process`, so the parsing
@@ -9,7 +9,8 @@
9
9
  * - no arguments -> scan the injected `cwd`
10
10
  * - exactly one positional -> scan the resolved project directory
11
11
  * - exactly one meta flag -> help or version (exit 0, no scan)
12
- * - anything else -> a deterministic error message
12
+ * - separated format/explain options may surround the single project path
13
+ * - malformed or unsupported shapes produce a deterministic error message
13
14
  *
14
15
  * `--help`/`-h`/`--version`/`-v` must stay standalone: combining them with any other token, or
15
16
  * combining them with each other, is rejected rather than given precedence.
@@ -22,6 +23,8 @@ export type ParsedCommand = {
22
23
  } | {
23
24
  kind: 'scan';
24
25
  projectPath: string;
26
+ format?: 'terminal' | 'json';
27
+ explain?: string;
25
28
  } | {
26
29
  kind: 'error';
27
30
  message: string;
@@ -1 +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"}
1
+ {"version":3,"file":"parseCliArgs.d.ts","sourceRoot":"","sources":["../../src/cli/parseCliArgs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,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,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACrF;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,CA+ChF"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Pure, deterministic argument parsing for the `v0.1.0` CLI.
2
+ * Pure, deterministic CLI argument parsing.
3
3
  *
4
4
  * This module only validates the argument shape and resolves the selected project path. It never
5
5
  * touches the filesystem, never calls the analyzer, and never accesses `process`, so the parsing
@@ -9,12 +9,15 @@
9
9
  * - no arguments -> scan the injected `cwd`
10
10
  * - exactly one positional -> scan the resolved project directory
11
11
  * - exactly one meta flag -> help or version (exit 0, no scan)
12
- * - anything else -> a deterministic error message
12
+ * - separated format/explain options may surround the single project path
13
+ * - malformed or unsupported shapes produce a deterministic error message
13
14
  *
14
15
  * `--help`/`-h`/`--version`/`-v` must stay standalone: combining them with any other token, or
15
16
  * combining them with each other, is rejected rather than given precedence.
16
17
  */
17
18
  import { resolve } from 'node:path';
19
+ import { isExactPackageRoot } from '../config/ignoreDependencies.js';
20
+ import { escapeControlCharacters } from '../reporters/terminalReporter.js';
18
21
  /** Help/version flags that must be used alone. */
19
22
  const HELP_FLAGS = new Set(['--help', '-h']);
20
23
  /** Version flags that must be used alone. */
@@ -33,48 +36,60 @@ const TOO_MANY_ARGUMENTS = 'Too many arguments: expected at most one project pat
33
36
  * the default project when no argument is supplied.
34
37
  */
35
38
  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.
39
+ if (args.length === 1 && HELP_FLAGS.has(args[0] ?? ''))
40
+ return { kind: 'help' };
41
+ if (args.length === 1 && VERSION_FLAGS.has(args[0] ?? ''))
42
+ return { kind: 'version' };
60
43
  const metaFlag = args.find((arg) => HELP_FLAGS.has(arg) || VERSION_FLAGS.has(arg));
61
- if (metaFlag !== undefined) {
44
+ if (metaFlag !== undefined)
62
45
  return { kind: 'error', message: metaFlagMustBeUsedAlone(metaFlag) };
46
+ let format;
47
+ let explain;
48
+ const paths = [];
49
+ const error = (body) => ({ kind: 'error', message: body + '\n' + HINT });
50
+ for (let index = 0; index < args.length; index += 1) {
51
+ const arg = args[index] ?? '';
52
+ if (arg === '--format' || arg === '--explain') {
53
+ if ((arg === '--format' && format !== undefined) ||
54
+ (arg === '--explain' && explain !== undefined)) {
55
+ return error(`Option ${arg} may be specified only once.`);
56
+ }
57
+ const value = args[index + 1];
58
+ if (value === undefined || value === '' || value.startsWith('-'))
59
+ return error(`Option ${arg} requires a value.`);
60
+ if (arg === '--format') {
61
+ if (value !== 'terminal' && value !== 'json')
62
+ return error(`Invalid value for --format: ${escapeControlCharacters(value)}. Expected terminal or json.`);
63
+ format = value;
64
+ }
65
+ else {
66
+ if (!isExactPackageRoot(value))
67
+ return error('Invalid value for --explain: expected an exact package root (name or @scope/name), at most 214 characters.');
68
+ explain = value;
69
+ }
70
+ index += 1;
71
+ }
72
+ else if (arg.startsWith('-'))
73
+ return { kind: 'error', message: unknownOptionMessage(arg) };
74
+ else
75
+ paths.push(arg);
63
76
  }
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 };
77
+ if (paths.length > 1)
78
+ return { kind: 'error', message: TOO_MANY_ARGUMENTS };
79
+ if (paths[0] === '')
80
+ return { kind: 'error', message: INVALID_EMPTY_PROJECT_PATH };
81
+ return {
82
+ kind: 'scan',
83
+ projectPath: paths[0] === undefined ? cwd : resolve(cwd, paths[0]),
84
+ ...(format === undefined ? {} : { format }),
85
+ ...(explain === undefined ? {} : { explain }),
86
+ };
72
87
  }
73
88
  /**
74
89
  * The error message for an unrecognized option.
75
90
  */
76
91
  function unknownOptionMessage(option) {
77
- return `Unknown option: ${option}\n${HINT}`;
92
+ return `Unknown option: ${escapeControlCharacters(option)}\n${HINT}`;
78
93
  }
79
94
  /**
80
95
  * The error message when a meta flag is combined with additional tokens.
@@ -1 +1 @@
1
- {"version":3,"file":"parseCliArgs.js","sourceRoot":"","sources":["../../src/cli/parseCliArgs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"parseCliArgs.js","sourceRoot":"","sources":["../../src/cli/parseCliArgs.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Asynchronous CLI orchestration for `v0.1.0`.
2
+ * Asynchronous CLI orchestration.
3
3
  *
4
4
  * `runCli` turns parsed arguments into a plain {@link CliResult}. It performs no process I/O of its
5
5
  * own: it never writes to stdout/stderr and never touches `process`. The thin adapter in
@@ -7,10 +7,9 @@
7
7
  *
8
8
  * The responsibilities here are:
9
9
  * - delegate argument validation to the pure {@link parseCliArgs};
10
- * - hand the configuration-only package names recognized in the project to the analyzer, which is
11
- * the only component allowed to turn evidence into an unused/missing category;
12
- * - run the static dependency scan with `analyzeProject`;
13
- * - render the report with the pure terminal reporter;
10
+ * - prepare one validated root/policy/detector context for the analyzer, which alone owns findings;
11
+ * - run one full detailed dependency scan;
12
+ * - render the selected terminal or JSON scan/query projection;
14
13
  * - decide the scan exit code from `hasDependencyIssues`, not from the report string;
15
14
  * - convert operational failures into a concise CLI error result.
16
15
  *
@@ -1 +1 @@
1
- {"version":3,"file":"runCli.d.ts","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAYH;;;;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"}
1
+ {"version":3,"file":"runCli.d.ts","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAsBH;;;;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;AAoBF;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAa7F"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Asynchronous CLI orchestration for `v0.1.0`.
2
+ * Asynchronous CLI orchestration.
3
3
  *
4
4
  * `runCli` turns parsed arguments into a plain {@link CliResult}. It performs no process I/O of its
5
5
  * own: it never writes to stdout/stderr and never touches `process`. The thin adapter in
@@ -7,23 +7,23 @@
7
7
  *
8
8
  * The responsibilities here are:
9
9
  * - delegate argument validation to the pure {@link parseCliArgs};
10
- * - hand the configuration-only package names recognized in the project to the analyzer, which is
11
- * the only component allowed to turn evidence into an unused/missing category;
12
- * - run the static dependency scan with `analyzeProject`;
13
- * - render the report with the pure terminal reporter;
10
+ * - prepare one validated root/policy/detector context for the analyzer, which alone owns findings;
11
+ * - run one full detailed dependency scan;
12
+ * - render the selected terminal or JSON scan/query projection;
14
13
  * - decide the scan exit code from `hasDependencyIssues`, not from the report string;
15
14
  * - convert operational failures into a concise CLI error result.
16
15
  *
17
16
  * It deliberately does not implement any scanning or dependency-analysis logic: that stays in
18
17
  * `src/core`, and the reporter stays in `src/reporters`.
19
18
  */
20
- import { AnalysisError, analyzeProject } from '../core/analyzeProject.js';
21
- import { findEslintManifestUsage } from '../detectors/eslintManifestConfig.js';
22
- import { EslintRcJsonError, findEslintRcJsonUsage } from '../detectors/eslintRcJsonConfig.js';
23
- import { findJestManifestUsage } from '../detectors/jestManifestConfig.js';
24
- import { formatTerminalReport, hasDependencyIssues } from '../reporters/terminalReporter.js';
19
+ import { ProjectConfigError } from '../config/readProjectConfig.js';
20
+ import { AnalysisError, analyzeProjectDetailed, projectAnalysisResult, projectPackageExplanation, } from '../core/analyzeProject.js';
21
+ import { createScanContext } from '../core/scanContext.js';
22
+ import { EslintRcJsonError } from '../detectors/eslintRcJsonConfig.js';
23
+ import { formatTerminalExplanation, formatTerminalReport, hasDependencyIssues, } from '../reporters/terminalReporter.js';
25
24
  import { ProjectManifestError } from '../scanner/projectManifest.js';
26
25
  import { SourceFilesError } from '../scanner/sourceFiles.js';
26
+ import { formatJsonReport } from '../reporters/jsonReporter.js';
27
27
  import { parseCliArgs } from './parseCliArgs.js';
28
28
  const HELP_MESSAGE = [
29
29
  'DepVitals',
@@ -31,12 +31,14 @@ const HELP_MESSAGE = [
31
31
  'A simple, lightweight dependency health checker for Node.js projects.',
32
32
  '',
33
33
  'Usage:',
34
- ' depvitals [project]',
34
+ ' depvitals [project] [--format terminal|json] [--explain <package>]',
35
35
  '',
36
36
  'Arguments:',
37
37
  ' project Project directory to analyze (default: current directory)',
38
38
  '',
39
39
  'Options:',
40
+ ' --format <format> Output format: terminal or json (default: terminal)',
41
+ ' --explain <package> Explain one exact package root (default: full scan)',
40
42
  ' -h, --help Show help',
41
43
  ' -v, --version Show version',
42
44
  ].join('\n');
@@ -57,7 +59,7 @@ export async function runCli(args, options) {
57
59
  case 'error':
58
60
  return { exitCode: 1, stdout: '', stderr: `${command.message}\n` };
59
61
  case 'scan':
60
- return await runScan(command.projectPath);
62
+ return await runScan(command, options.version);
61
63
  }
62
64
  }
63
65
  /**
@@ -67,54 +69,47 @@ export async function runCli(args, options) {
67
69
  * empty stdout). Any other thrown value is surfaced through a generic fallback message so the CLI
68
70
  * never leaks internal error objects and never leaves an unhandled rejection.
69
71
  */
70
- async function runScan(projectPath) {
71
- let result;
72
+ async function runScan(command, version) {
73
+ const projectPath = command.projectPath;
72
74
  try {
73
- // Legacy ESLint configuration contributes configuration-only names. They are passed through the
74
- // analyzer's config handoff, which merges them into `usedNames` only, so they can suppress an
75
- // unused finding and can never create a missing one.
76
- const configUsedNames = await collectConfigUsedNames(projectPath);
77
- result = await analyzeProject(projectPath, { configUsedNames });
78
- }
79
- catch (error) {
80
- if (isOperationalError(error)) {
81
- return { exitCode: 1, stdout: '', stderr: `${error.message}\n` };
75
+ const context = await createScanContext(projectPath);
76
+ const detailed = await analyzeProjectDetailed(context);
77
+ if (command.explain !== undefined) {
78
+ const result = projectPackageExplanation(detailed, command.explain);
79
+ return {
80
+ exitCode: result.exitCode,
81
+ stdout: command.format === 'json'
82
+ ? formatJsonReport({ mode: 'explain', result }, version)
83
+ : formatTerminalExplanation(result),
84
+ stderr: '',
85
+ };
82
86
  }
87
+ const result = projectAnalysisResult(detailed);
83
88
  return {
84
- exitCode: 1,
85
- stdout: '',
86
- stderr: `${unexpectedErrorMessage(projectPath, error)}\n`,
89
+ exitCode: hasDependencyIssues(result) ? 1 : 0,
90
+ stdout: command.format === 'json'
91
+ ? formatJsonReport({ mode: 'scan', result: detailed }, version)
92
+ : formatTerminalReport(result),
93
+ stderr: '',
87
94
  };
88
95
  }
89
- const hasIssues = hasDependencyIssues(result);
90
- return { exitCode: hasIssues ? 1 : 0, stdout: formatTerminalReport(result), stderr: '' };
91
- }
92
- /**
93
- * Collect the configuration-only package names of one project.
94
- *
95
- * Both legacy ESLint sources share one precedence computation: a hard barrier disables both, and
96
- * otherwise `.eslintrc.json` wins over the `package.json#eslintConfig` block, so the two readers are
97
- * mutually exclusive and the union never combines contradictory configuration. The `package.json#jest`
98
- * reader is independent of the ESLint rules but obeys the same style of guard, producing nothing once
99
- * a root `jest.config.*` file exists. The analyzer re-validates and sorts the merged hints, so no
100
- * ordering is imposed here.
101
- */
102
- async function collectConfigUsedNames(projectPath) {
103
- const manifestNames = await findEslintManifestUsage(projectPath);
104
- const eslintRcJsonNames = await findEslintRcJsonUsage(projectPath);
105
- const jestNames = await findJestManifestUsage(projectPath);
106
- return new Set([...manifestNames, ...eslintRcJsonNames, ...jestNames]);
96
+ catch (error) {
97
+ if (isOperationalError(error))
98
+ return { exitCode: 1, stdout: '', stderr: `${error.message}\n` };
99
+ return { exitCode: 1, stdout: '', stderr: `${unexpectedErrorMessage(projectPath, error)}\n` };
100
+ }
107
101
  }
108
102
  /**
109
103
  * Whether the thrown value is a scanner error the CLI knows how to render. Only the existing typed
110
- * error classes plus the unusable-`.eslintrc.json` error count; everything else is treated as an
104
+ * error classes plus configuration errors count; everything else is treated as an
111
105
  * unexpected internal failure.
112
106
  */
113
107
  function isOperationalError(error) {
114
108
  return (error instanceof ProjectManifestError ||
115
109
  error instanceof SourceFilesError ||
116
110
  error instanceof AnalysisError ||
117
- error instanceof EslintRcJsonError);
111
+ error instanceof EslintRcJsonError ||
112
+ error instanceof ProjectConfigError);
118
113
  }
119
114
  /**
120
115
  * The fallback message for an unexpected thrown value. The path is always included so the failure
@@ -1 +1 @@
1
- {"version":3,"file":"runCli.js","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runCli.js","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /** Shared exact-root grammar for dependency exclusions and explanation input; no normalization. */
2
+ export declare function isExactPackageRoot(name: string): boolean;
3
+ /**
4
+ * Preserve exact case and spelling; validate whole entries before sorting/deduplicating.
5
+ * This bounded grammar is independent of source subpath normalization and builtin classification.
6
+ * configPath is diagnostic context only. No inventory, filesystem or registry is consulted.
7
+ */
8
+ export declare function normalizeIgnoreDependencies(rawNames: readonly string[], configPath: string): readonly string[];
9
+ //# sourceMappingURL=ignoreDependencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignoreDependencies.d.ts","sourceRoot":"","sources":["../../src/config/ignoreDependencies.ts"],"names":[],"mappings":"AAMA,mGAAmG;AACnG,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,UAAU,EAAE,MAAM,GACjB,SAAS,MAAM,EAAE,CAUnB"}