depvitals 0.2.0 → 0.3.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 (54) hide show
  1. package/README.md +36 -40
  2. package/dist/cli/runCli.d.ts.map +1 -1
  3. package/dist/cli/runCli.js +9 -4
  4. package/dist/cli/runCli.js.map +1 -1
  5. package/dist/config/ignoreDependencies.d.ts +7 -0
  6. package/dist/config/ignoreDependencies.d.ts.map +1 -0
  7. package/dist/config/ignoreDependencies.js +18 -0
  8. package/dist/config/ignoreDependencies.js.map +1 -0
  9. package/dist/config/ignorePaths.d.ts +13 -0
  10. package/dist/config/ignorePaths.d.ts.map +1 -0
  11. package/dist/config/ignorePaths.js +47 -0
  12. package/dist/config/ignorePaths.js.map +1 -0
  13. package/dist/config/projectConfigError.d.ts +7 -0
  14. package/dist/config/projectConfigError.d.ts.map +1 -0
  15. package/dist/config/projectConfigError.js +10 -0
  16. package/dist/config/projectConfigError.js.map +1 -0
  17. package/dist/config/readProjectConfig.d.ts +23 -0
  18. package/dist/config/readProjectConfig.d.ts.map +1 -0
  19. package/dist/config/readProjectConfig.js +106 -0
  20. package/dist/config/readProjectConfig.js.map +1 -0
  21. package/dist/core/analyzeProject.d.ts +5 -1
  22. package/dist/core/analyzeProject.d.ts.map +1 -1
  23. package/dist/core/analyzeProject.js +37 -29
  24. package/dist/core/analyzeProject.js.map +1 -1
  25. package/dist/detectors/eslintManifestConfig.d.ts.map +1 -1
  26. package/dist/detectors/eslintManifestConfig.js +7 -4
  27. package/dist/detectors/eslintManifestConfig.js.map +1 -1
  28. package/dist/detectors/eslintRcJsonConfig.d.ts.map +1 -1
  29. package/dist/detectors/eslintRcJsonConfig.js +2 -1
  30. package/dist/detectors/eslintRcJsonConfig.js.map +1 -1
  31. package/dist/detectors/jestManifestConfig.d.ts.map +1 -1
  32. package/dist/detectors/jestManifestConfig.js +6 -4
  33. package/dist/detectors/jestManifestConfig.js.map +1 -1
  34. package/dist/scanner/moduleSpecifiers.d.ts +2 -2
  35. package/dist/scanner/moduleSpecifiers.d.ts.map +1 -1
  36. package/dist/scanner/moduleSpecifiers.js +1111 -178
  37. package/dist/scanner/moduleSpecifiers.js.map +1 -1
  38. package/dist/scanner/packageSpecifier.d.ts +26 -2
  39. package/dist/scanner/packageSpecifier.d.ts.map +1 -1
  40. package/dist/scanner/packageSpecifier.js +70 -2
  41. package/dist/scanner/packageSpecifier.js.map +1 -1
  42. package/dist/scanner/projectManifest.d.ts +19 -3
  43. package/dist/scanner/projectManifest.d.ts.map +1 -1
  44. package/dist/scanner/projectManifest.js +51 -12
  45. package/dist/scanner/projectManifest.js.map +1 -1
  46. package/dist/scanner/scriptUsage.d.ts +2 -1
  47. package/dist/scanner/scriptUsage.d.ts.map +1 -1
  48. package/dist/scanner/scriptUsage.js +182 -37
  49. package/dist/scanner/scriptUsage.js.map +1 -1
  50. package/dist/scanner/sourceFiles.d.ts +16 -2
  51. package/dist/scanner/sourceFiles.d.ts.map +1 -1
  52. package/dist/scanner/sourceFiles.js +12 -6
  53. package/dist/scanner/sourceFiles.js.map +1 -1
  54. package/package.json +1 -1
package/README.md CHANGED
@@ -1,70 +1,66 @@
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`.
8
13
 
9
14
  ## Quick start
10
15
 
11
- Requires **Node.js 22.13.0 or newer**. From a directory containing `package.json`:
16
+ Requires **Node.js 22.13.0 or newer**. Scan the current directory containing `package.json`, or pass a project path:
12
17
 
13
18
  ```sh
14
19
  npx depvitals
20
+ npx depvitals ./path/to/project
15
21
  ```
16
22
 
17
- Scan an explicit project path, or request standalone help/version:
23
+ ### Install globally
18
24
 
19
25
  ```sh
20
- npx depvitals ./path/to/project
21
- npx depvitals --help
22
- npx depvitals --version
26
+ npm i -g depvitals
27
+ depvitals
28
+ depvitals ./path/to/project
23
29
  ```
24
30
 
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).
31
+ Use `depvitals --help` or `depvitals --version` for standalone help/version; the same flags work with `npx depvitals`.
26
32
 
27
- ## Understand the results
33
+ 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).
28
34
 
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. |
35
+ ## Results
34
36
 
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.
37
+ | Finding | Meaning |
38
+ | ---------------------- | -------------------------------------------------------------------------------------- |
39
+ | Unused dependencies | Declared in `dependencies`, without supported usage evidence. |
40
+ | Unused devDependencies | The same check for `devDependencies`. |
41
+ | Missing dependencies | Referenced by supported source imports/exports/requires, but undeclared in all groups. |
36
42
 
37
- A scan can report:
43
+ **Missing means undeclared, not uninstalled. Unused is not proof of safe removal.** Review findings before editing your manifest. Peer and optional dependencies suppress missing findings and are never reported unused.
38
44
 
39
- ```text
40
- DepVitals
45
+ 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.
41
46
 
42
- Unused dependencies (1)
43
- lodash
47
+ ## Optional configuration
44
48
 
45
- Unused devDependencies (1)
46
- echo-only
49
+ Requires DepVitals **0.3.0 or newer**. Create `depvitals.config.json` at the scanned project root:
47
50
 
48
- Missing dependencies (1)
49
- undeclared-pkg
51
+ ```json
52
+ {
53
+ "ignorePaths": ["examples", "src/generated"],
54
+ "ignoreDependencies": ["some-adapter"]
55
+ }
50
56
  ```
51
57
 
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.
53
-
54
- ## Coverage and fit
55
-
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.
57
-
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.
59
-
60
- ## Limits and update check
61
-
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.
58
+ `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
59
 
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.
60
+ ## Scope and privacy
65
61
 
66
- ## More
62
+ 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, JSON output or automatic fix; see [supported patterns and limits](https://github.com/MatiasRicardi/depvitals/blob/main/docs/reference.md).
67
63
 
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)
64
+ 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. 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
65
 
70
- [MIT license](https://github.com/MatiasRicardi/depvitals/blob/main/LICENSE).
66
+ [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)
@@ -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;;;;;;;;;;;;;;;;;;GAkBG;AAaH;;;;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"}
@@ -17,12 +17,13 @@
17
17
  * It deliberately does not implement any scanning or dependency-analysis logic: that stays in
18
18
  * `src/core`, and the reporter stays in `src/reporters`.
19
19
  */
20
+ import { readProjectConfig, ProjectConfigError } from '../config/readProjectConfig.js';
20
21
  import { AnalysisError, analyzeProject } from '../core/analyzeProject.js';
21
22
  import { findEslintManifestUsage } from '../detectors/eslintManifestConfig.js';
22
23
  import { EslintRcJsonError, findEslintRcJsonUsage } from '../detectors/eslintRcJsonConfig.js';
23
24
  import { findJestManifestUsage } from '../detectors/jestManifestConfig.js';
24
25
  import { formatTerminalReport, hasDependencyIssues } from '../reporters/terminalReporter.js';
25
- import { ProjectManifestError } from '../scanner/projectManifest.js';
26
+ import { loadProjectManifest, ProjectManifestError } from '../scanner/projectManifest.js';
26
27
  import { SourceFilesError } from '../scanner/sourceFiles.js';
27
28
  import { parseCliArgs } from './parseCliArgs.js';
28
29
  const HELP_MESSAGE = [
@@ -70,11 +71,14 @@ export async function runCli(args, options) {
70
71
  async function runScan(projectPath) {
71
72
  let result;
72
73
  try {
74
+ // Validate mandatory root metadata, then the selected-root policy, before detector reads.
75
+ await loadProjectManifest(projectPath);
76
+ const config = await readProjectConfig(projectPath);
73
77
  // Legacy ESLint configuration contributes configuration-only names. They are passed through the
74
78
  // analyzer's config handoff, which merges them into `usedNames` only, so they can suppress an
75
79
  // unused finding and can never create a missing one.
76
80
  const configUsedNames = await collectConfigUsedNames(projectPath);
77
- result = await analyzeProject(projectPath, { configUsedNames });
81
+ result = await analyzeProject(projectPath, { ...config, configUsedNames });
78
82
  }
79
83
  catch (error) {
80
84
  if (isOperationalError(error)) {
@@ -107,14 +111,15 @@ async function collectConfigUsedNames(projectPath) {
107
111
  }
108
112
  /**
109
113
  * 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
114
+ * error classes plus configuration errors count; everything else is treated as an
111
115
  * unexpected internal failure.
112
116
  */
113
117
  function isOperationalError(error) {
114
118
  return (error instanceof ProjectManifestError ||
115
119
  error instanceof SourceFilesError ||
116
120
  error instanceof AnalysisError ||
117
- error instanceof EslintRcJsonError);
121
+ error instanceof EslintRcJsonError ||
122
+ error instanceof ProjectConfigError);
118
123
  }
119
124
  /**
120
125
  * 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":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACvF,OAAO,EAAE,aAAa,EAAuB,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC/F,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC9F,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAsBjD,MAAM,YAAY,GAAG;IACnB,WAAW;IACX,EAAE;IACF,uEAAuE;IACvE,EAAE;IACF,QAAQ;IACR,uBAAuB;IACvB,EAAE;IACF,YAAY;IACZ,8EAA8E;IAC9E,EAAE;IACF,UAAU;IACV,8BAA8B;IAC9B,iCAAiC;CAClC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAuB,EAAE,OAAmB;IACvE,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAEhD,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,MAAM;YACT,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAClE,KAAK,SAAS;YACZ,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACrE,KAAK,OAAO;YACV,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QACrE,KAAK,MAAM;YACT,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,OAAO,CAAC,WAAmB;IACxC,IAAI,MAAsB,CAAC;IAE3B,IAAI,CAAC;QACH,0FAA0F;QAC1F,MAAM,mBAAmB,CAAC,WAAW,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;QAEpD,gGAAgG;QAChG,8FAA8F;QAC9F,qDAAqD;QACrD,MAAM,eAAe,GAAG,MAAM,sBAAsB,CAAC,WAAW,CAAC,CAAC;QAElE,MAAM,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,EAAE,GAAG,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;QACnE,CAAC;QAED,OAAO;YACL,QAAQ,EAAE,CAAC;YACX,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,GAAG,sBAAsB,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI;SAC1D,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE9C,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,oBAAoB,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAC3F,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,sBAAsB,CAAC,WAAmB;IACvD,MAAM,aAAa,GAAG,MAAM,uBAAuB,CAAC,WAAW,CAAC,CAAC;IACjE,MAAM,iBAAiB,GAAG,MAAM,qBAAqB,CAAC,WAAW,CAAC,CAAC;IACnE,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAAC,WAAW,CAAC,CAAC;IAE3D,OAAO,IAAI,GAAG,CAAS,CAAC,GAAG,aAAa,EAAE,GAAG,iBAAiB,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC;AACjF,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CACzB,KAAc;IAGd,OAAO,CACL,KAAK,YAAY,oBAAoB;QACrC,KAAK,YAAY,gBAAgB;QACjC,KAAK,YAAY,aAAa;QAC9B,KAAK,YAAY,iBAAiB;QAClC,KAAK,YAAY,kBAAkB,CACpC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,sBAAsB,CAAC,WAAmB,EAAE,KAAc;IACjE,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9D,OAAO,4CAA4C,WAAW,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;IACrF,CAAC;IAED,OAAO,4CAA4C,WAAW,GAAG,CAAC;AACpE,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Preserve exact case and spelling; validate whole entries before sorting/deduplicating.
3
+ * This bounded grammar is independent of source subpath normalization and builtin classification.
4
+ * configPath is diagnostic context only. No inventory, filesystem or registry is consulted.
5
+ */
6
+ export declare function normalizeIgnoreDependencies(rawNames: readonly string[], configPath: string): readonly string[];
7
+ //# sourceMappingURL=ignoreDependencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignoreDependencies.d.ts","sourceRoot":"","sources":["../../src/config/ignoreDependencies.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,UAAU,EAAE,MAAM,GACjB,SAAS,MAAM,EAAE,CAUnB"}
@@ -0,0 +1,18 @@
1
+ /** Exact identifier validation; analysis applies validated names only to final findings. */
2
+ import { ProjectConfigError } from './projectConfigError.js';
3
+ const COMPONENT = '[A-Za-z0-9][A-Za-z0-9._-]*';
4
+ const IDENTIFIER = new RegExp(`^(?:${COMPONENT}|@${COMPONENT}/${COMPONENT})$`, 'u');
5
+ /**
6
+ * Preserve exact case and spelling; validate whole entries before sorting/deduplicating.
7
+ * This bounded grammar is independent of source subpath normalization and builtin classification.
8
+ * configPath is diagnostic context only. No inventory, filesystem or registry is consulted.
9
+ */
10
+ export function normalizeIgnoreDependencies(rawNames, configPath) {
11
+ for (const [index, name] of rawNames.entries()) {
12
+ if (name.length > 214 || IDENTIFIER.exec(name)?.[0] !== name) {
13
+ throw new ProjectConfigError(`${configPath} field ignoreDependencies[${String(index)}] must be an exact package root (name or @scope/name), at most 214 characters; components must start with ASCII alphanumeric and contain only ASCII alphanumeric, '.', '_' or '-'`, 'invalid-shape');
14
+ }
15
+ }
16
+ return Object.freeze([...new Set(rawNames)].sort());
17
+ }
18
+ //# sourceMappingURL=ignoreDependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignoreDependencies.js","sourceRoot":"","sources":["../../src/config/ignoreDependencies.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,SAAS,GAAG,4BAA4B,CAAC;AAC/C,MAAM,UAAU,GAAG,IAAI,MAAM,CAAC,OAAO,SAAS,KAAK,SAAS,IAAI,SAAS,IAAI,EAAE,GAAG,CAAC,CAAC;AAEpF;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CACzC,QAA2B,EAC3B,UAAkB;IAElB,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/C,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC7D,MAAM,IAAI,kBAAkB,CAC1B,GAAG,UAAU,6BAA6B,MAAM,CAAC,KAAK,CAAC,mLAAmL,EAC1O,eAAe,CAChB,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Validate every raw rule before returning a normalized, sorted, deduplicated snapshot. Both slash
3
+ * spellings are config separators on every host. No rule destination is probed or resolved.
4
+ * configPath is diagnostic context supplied by the caller, not a file to read here.
5
+ */
6
+ export declare function normalizeIgnorePaths(rawRules: readonly string[], configPath: string): readonly string[];
7
+ /**
8
+ * Compare a canonical '/'-separated project-relative discovery path against validated rules.
9
+ * The caller converts native discovery separators; this matcher does not resolve or normalize
10
+ * candidate filenames. Matching is case-sensitive, extension-independent and segment-bounded.
11
+ */
12
+ export declare function matchesIgnoredPath(projectRelativePath: string, normalizedRules: readonly string[]): boolean;
13
+ //# sourceMappingURL=ignorePaths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignorePaths.d.ts","sourceRoot":"","sources":["../../src/config/ignorePaths.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,UAAU,EAAE,MAAM,GACjB,SAAS,MAAM,EAAE,CA8BnB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,mBAAmB,EAAE,MAAM,EAC3B,eAAe,EAAE,SAAS,MAAM,EAAE,GACjC,OAAO,CAIT"}
@@ -0,0 +1,47 @@
1
+ /** Literal path policy shared by configuration validation and source discovery. */
2
+ import { ProjectConfigError } from './projectConfigError.js';
3
+ /**
4
+ * Validate every raw rule before returning a normalized, sorted, deduplicated snapshot. Both slash
5
+ * spellings are config separators on every host. No rule destination is probed or resolved.
6
+ * configPath is diagnostic context supplied by the caller, not a file to read here.
7
+ */
8
+ export function normalizeIgnorePaths(rawRules, configPath) {
9
+ const normalized = rawRules.map((rule, index) => {
10
+ const fail = (reason) => {
11
+ throw new ProjectConfigError(`${configPath} field ignorePaths[${String(index)}] ${reason}`, 'invalid-shape');
12
+ };
13
+ // Check the original spelling: normalization must never hide a rooted or drive-relative rule.
14
+ if (rule.startsWith('/') || rule.startsWith('\\') || /^[A-Za-z]:/.test(rule)) {
15
+ fail('must be project-relative; absolute, rooted, UNC and drive-relative paths are unsupported');
16
+ }
17
+ if (rule !== rule.trim())
18
+ fail('must not have leading or trailing whitespace');
19
+ if (rule.includes(':'))
20
+ fail('must not contain a colon');
21
+ if (/\p{Cc}/u.test(rule))
22
+ fail('must not contain a control character');
23
+ if (['*', '?', '[', ']', '{', '}', '!'].some((character) => rule.includes(character))) {
24
+ fail('contains unsupported pattern characters; use a literal file or subtree path');
25
+ }
26
+ const segments = rule.replaceAll('\\', '/').split('/');
27
+ if (segments.includes('..'))
28
+ fail('must not contain a .. traversal segment');
29
+ const result = segments.filter((segment) => segment !== '' && segment !== '.').join('/');
30
+ if (result.length === 0)
31
+ fail('must name a nonempty path, not the project root');
32
+ // Dot/separator removal can expose whitespace that was interior in the raw spelling.
33
+ if (result !== result.trim())
34
+ fail('must not have leading or trailing whitespace after normalization');
35
+ return result;
36
+ });
37
+ return Object.freeze([...new Set(normalized)].sort());
38
+ }
39
+ /**
40
+ * Compare a canonical '/'-separated project-relative discovery path against validated rules.
41
+ * The caller converts native discovery separators; this matcher does not resolve or normalize
42
+ * candidate filenames. Matching is case-sensitive, extension-independent and segment-bounded.
43
+ */
44
+ export function matchesIgnoredPath(projectRelativePath, normalizedRules) {
45
+ return normalizedRules.some((rule) => projectRelativePath === rule || projectRelativePath.startsWith(`${rule}/`));
46
+ }
47
+ //# sourceMappingURL=ignorePaths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignorePaths.js","sourceRoot":"","sources":["../../src/config/ignorePaths.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAA2B,EAC3B,UAAkB;IAElB,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC9C,MAAM,IAAI,GAAG,CAAC,MAAc,EAAS,EAAE;YACrC,MAAM,IAAI,kBAAkB,CAC1B,GAAG,UAAU,sBAAsB,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,EAAE,EAC7D,eAAe,CAChB,CAAC;QACJ,CAAC,CAAC;QACF,8FAA8F;QAC9F,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7E,IAAI,CACF,0FAA0F,CAC3F,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,8CAA8C,CAAC,CAAC;QAC/E,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACzD,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,sCAAsC,CAAC,CAAC;QACvE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;YACtF,IAAI,CAAC,6EAA6E,CAAC,CAAC;QACtF,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACvD,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,yCAAyC,CAAC,CAAC;QAC7E,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,IAAI,CAAC,iDAAiD,CAAC,CAAC;QACjF,qFAAqF;QACrF,IAAI,MAAM,KAAK,MAAM,CAAC,IAAI,EAAE;YAC1B,IAAI,CAAC,kEAAkE,CAAC,CAAC;QAC3E,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,mBAA2B,EAC3B,eAAkC;IAElC,OAAO,eAAe,CAAC,IAAI,CACzB,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,KAAK,IAAI,IAAI,mBAAmB,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,CACrF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ export type ProjectConfigErrorCode = 'unreadable' | 'invalid-json' | 'invalid-shape';
2
+ /** Operational configuration failure; broken present data must never become empty defaults. */
3
+ export declare class ProjectConfigError extends Error {
4
+ readonly code: ProjectConfigErrorCode;
5
+ constructor(message: string, code: ProjectConfigErrorCode, cause?: unknown);
6
+ }
7
+ //# sourceMappingURL=projectConfigError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectConfigError.d.ts","sourceRoot":"","sources":["../../src/config/projectConfigError.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG,YAAY,GAAG,cAAc,GAAG,eAAe,CAAC;AAErF,+FAA+F;AAC/F,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;gBAE1B,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,CAAC,EAAE,OAAO;CAK3E"}
@@ -0,0 +1,10 @@
1
+ /** Operational configuration failure; broken present data must never become empty defaults. */
2
+ export class ProjectConfigError extends Error {
3
+ code;
4
+ constructor(message, code, cause) {
5
+ super(message, cause === undefined ? undefined : { cause });
6
+ this.name = 'ProjectConfigError';
7
+ this.code = code;
8
+ }
9
+ }
10
+ //# sourceMappingURL=projectConfigError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectConfigError.js","sourceRoot":"","sources":["../../src/config/projectConfigError.ts"],"names":[],"mappings":"AAEA,+FAA+F;AAC/F,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,IAAI,CAAyB;IAEtC,YAAY,OAAe,EAAE,IAA4B,EAAE,KAAe;QACxE,KAAK,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
@@ -0,0 +1,23 @@
1
+ export type RawProjectConfig = {
2
+ readonly ignorePaths: readonly string[];
3
+ readonly ignoreDependencies: readonly string[];
4
+ };
5
+ export { ProjectConfigError, type ProjectConfigErrorCode } from './projectConfigError.js';
6
+ /**
7
+ * Read exactly the canonical config entry in the selected root. No parents, alternatives or rule
8
+ * destinations are consulted. Only absence is defaults. Present non-regular/unreadable entries and
9
+ * malformed documents fail as a whole. Existing root errors use the shared SourceFilesError guard.
10
+ *
11
+ * Strings retain their original spelling, order and duplicates for later semantic validators.
12
+ * A single leading UTF-8 BOM is accepted; all remaining syntax is native strict JSON.parse.
13
+ * Stable entry checks do not claim adversarial protection against replacement between I/O calls.
14
+ */
15
+ export declare function readRawProjectConfig(projectRoot: string): Promise<RawProjectConfig>;
16
+ /** Validated internal snapshot; no policy is applied to discovery or findings here. */
17
+ export type ProjectConfig = {
18
+ readonly ignorePaths: readonly string[];
19
+ readonly ignoreDependencies: readonly string[];
20
+ };
21
+ /** Read once, validate all path/name rules, and return no partial configuration on failure. */
22
+ export declare function readProjectConfig(projectRoot: string): Promise<ProjectConfig>;
23
+ //# sourceMappingURL=readProjectConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readProjectConfig.d.ts","sourceRoot":"","sources":["../../src/config/readProjectConfig.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;CAChD,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAI1F;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwDzF;AAwCD,uFAAuF;AACvF,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;CAChD,CAAC;AAEF,+FAA+F;AAC/F,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAOnF"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Internal, root-only JSON configuration readers. The CLI loads readProjectConfig on scans only;
3
+ * only that reader returns semantically validated rules.
4
+ */
5
+ import { lstat, readFile, readdir } from 'node:fs/promises';
6
+ import { join, resolve } from 'node:path';
7
+ import { assertReadableRoot } from '../scanner/sourceFiles.js';
8
+ import { normalizeIgnoreDependencies } from './ignoreDependencies.js';
9
+ import { normalizeIgnorePaths } from './ignorePaths.js';
10
+ import { ProjectConfigError } from './projectConfigError.js';
11
+ export { ProjectConfigError } from './projectConfigError.js';
12
+ const CONFIG_FILENAME = 'depvitals.config.json';
13
+ /**
14
+ * Read exactly the canonical config entry in the selected root. No parents, alternatives or rule
15
+ * destinations are consulted. Only absence is defaults. Present non-regular/unreadable entries and
16
+ * malformed documents fail as a whole. Existing root errors use the shared SourceFilesError guard.
17
+ *
18
+ * Strings retain their original spelling, order and duplicates for later semantic validators.
19
+ * A single leading UTF-8 BOM is accepted; all remaining syntax is native strict JSON.parse.
20
+ * Stable entry checks do not claim adversarial protection against replacement between I/O calls.
21
+ */
22
+ export async function readRawProjectConfig(projectRoot) {
23
+ const root = resolve(projectRoot);
24
+ const path = join(root, CONFIG_FILENAME);
25
+ await assertReadableRoot(root);
26
+ let entries;
27
+ try {
28
+ // Exact entry-name comparison also enforces canonical casing on case-insensitive hosts.
29
+ entries = await readdir(root);
30
+ }
31
+ catch (error) {
32
+ throw unreadable(path, error);
33
+ }
34
+ if (!entries.includes(CONFIG_FILENAME))
35
+ return emptyConfig();
36
+ let info;
37
+ try {
38
+ info = await lstat(path);
39
+ }
40
+ catch (error) {
41
+ // The directory entry was already present, so disappearance is an error, not absence.
42
+ throw unreadable(path, error);
43
+ }
44
+ if (!info.isFile()) {
45
+ throw new ProjectConfigError(`${path} must be a regular file; symlinks and non-regular entries are not read`, 'unreadable');
46
+ }
47
+ let text;
48
+ try {
49
+ text = await readFile(path, 'utf8');
50
+ }
51
+ catch (error) {
52
+ throw unreadable(path, error);
53
+ }
54
+ let parsed;
55
+ try {
56
+ parsed = JSON.parse(text.charCodeAt(0) === 0xfeff ? text.slice(1) : text);
57
+ }
58
+ catch (error) {
59
+ throw new ProjectConfigError(`${path} is not valid JSON`, 'invalid-json', error);
60
+ }
61
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
62
+ throw new ProjectConfigError(`${path} must contain a JSON object`, 'invalid-shape');
63
+ }
64
+ for (const key of Object.keys(parsed)) {
65
+ if (key !== 'ignorePaths' && key !== 'ignoreDependencies') {
66
+ throw new ProjectConfigError(`${path} has unsupported field ${JSON.stringify(key)}; only ignorePaths and ignoreDependencies are supported`, 'invalid-shape');
67
+ }
68
+ }
69
+ const config = parsed;
70
+ return Object.freeze({
71
+ ignorePaths: readStrings(config['ignorePaths'], 'ignorePaths', path),
72
+ ignoreDependencies: readStrings(config['ignoreDependencies'], 'ignoreDependencies', path),
73
+ });
74
+ }
75
+ function readStrings(value, field, path) {
76
+ if (value === undefined)
77
+ return Object.freeze([]);
78
+ if (!Array.isArray(value)) {
79
+ throw new ProjectConfigError(`${path} field ${field} must be an array of strings`, 'invalid-shape');
80
+ }
81
+ const strings = [];
82
+ for (let index = 0; index < value.length; index++) {
83
+ const entry = value[index];
84
+ if (typeof entry !== 'string' || entry.trim().length === 0) {
85
+ throw new ProjectConfigError(`${path} field ${field}[${String(index)}] must be a nonempty, non-whitespace string`, 'invalid-shape');
86
+ }
87
+ strings.push(entry);
88
+ }
89
+ return Object.freeze(strings);
90
+ }
91
+ function emptyConfig() {
92
+ return Object.freeze({ ignorePaths: Object.freeze([]), ignoreDependencies: Object.freeze([]) });
93
+ }
94
+ function unreadable(path, cause) {
95
+ return new ProjectConfigError(`Could not read ${CONFIG_FILENAME} at ${path}`, 'unreadable', cause);
96
+ }
97
+ /** Read once, validate all path/name rules, and return no partial configuration on failure. */
98
+ export async function readProjectConfig(projectRoot) {
99
+ const raw = await readRawProjectConfig(projectRoot);
100
+ const path = join(resolve(projectRoot), CONFIG_FILENAME);
101
+ return Object.freeze({
102
+ ignorePaths: normalizeIgnorePaths(raw.ignorePaths, path),
103
+ ignoreDependencies: normalizeIgnoreDependencies(raw.ignoreDependencies, path),
104
+ });
105
+ }
106
+ //# sourceMappingURL=readProjectConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readProjectConfig.js","sourceRoot":"","sources":["../../src/config/readProjectConfig.ts"],"names":[],"mappings":"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"}
@@ -92,6 +92,10 @@ export type AnalysisOptions = {
92
92
  * rule is active yet, so the default keeps every report byte-for-byte identical.
93
93
  */
94
94
  readonly configUsedNames?: ConfigUsageHints | undefined;
95
+ /** Validated, normalized literal paths excluded from source discovery only; omitted is empty. */
96
+ readonly ignorePaths?: readonly string[] | undefined;
97
+ /** Validated exact package roots omitted from final findings only; never usage evidence. */
98
+ readonly ignoreDependencies?: readonly string[] | undefined;
95
99
  };
96
100
  /**
97
101
  * Why the analysis could not complete.
@@ -121,7 +125,7 @@ export declare class AnalysisError extends Error {
121
125
  * project is never written to.
122
126
  *
123
127
  * @param projectRoot - Directory to analyze.
124
- * @param options - Optional {@link ConfigUsageHints}; an omitted or empty set changes nothing.
128
+ * @param options - Optional static tool hints and validated source exclusions; omitted inputs change nothing.
125
129
  * @throws {AnalysisError} when a discovered source file cannot be read or cannot be safely analyzed.
126
130
  * @throws {ProjectManifestError} when the manifest is missing, unreadable, invalid or malformed.
127
131
  * @throws {SourceFilesError} when the root is missing, is not a directory, or cannot be read.
@@ -1 +1 @@
1
- {"version":3,"file":"analyzeProject.d.ts","sourceRoot":"","sources":["../../src/core/analyzeProject.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAWH;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,uDAAuD;IACvD,qBAAqB,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,+FAA+F;IAC/F,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,gBAAgB,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AAEnD;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CACzD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAEvE;;;;;;;GAOG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;gBAErB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,CAAC,EAAE,OAAO;CAKtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAqDzB"}
1
+ {"version":3,"file":"analyzeProject.d.ts","sourceRoot":"","sources":["../../src/core/analyzeProject.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAeH;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,uDAAuD;IACvD,qBAAqB,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,+FAA+F;IAC/F,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,gBAAgB,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AAEnD;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACxD,iGAAiG;IACjG,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACrD,4FAA4F;IAC5F,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAC7D,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAEvE;;;;;;;GAOG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;gBAErB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,CAAC,EAAE,OAAO;CAKtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CA6DzB"}