depvitals 0.1.2 → 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 (86) hide show
  1. package/README.md +39 -61
  2. package/dist/cli/entry.d.ts +59 -0
  3. package/dist/cli/entry.d.ts.map +1 -0
  4. package/dist/cli/entry.js +95 -0
  5. package/dist/cli/entry.js.map +1 -0
  6. package/dist/cli/index.js +14 -18
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/cli/notifier/eligibility.d.ts +65 -0
  9. package/dist/cli/notifier/eligibility.d.ts.map +1 -0
  10. package/dist/cli/notifier/eligibility.js +123 -0
  11. package/dist/cli/notifier/eligibility.js.map +1 -0
  12. package/dist/cli/notifier/registryLookup.d.ts +111 -0
  13. package/dist/cli/notifier/registryLookup.d.ts.map +1 -0
  14. package/dist/cli/notifier/registryLookup.js +211 -0
  15. package/dist/cli/notifier/registryLookup.js.map +1 -0
  16. package/dist/cli/notifier/updateCache.d.ts +101 -0
  17. package/dist/cli/notifier/updateCache.d.ts.map +1 -0
  18. package/dist/cli/notifier/updateCache.js +352 -0
  19. package/dist/cli/notifier/updateCache.js.map +1 -0
  20. package/dist/cli/notifier/updateCheck.d.ts +88 -0
  21. package/dist/cli/notifier/updateCheck.d.ts.map +1 -0
  22. package/dist/cli/notifier/updateCheck.js +166 -0
  23. package/dist/cli/notifier/updateCheck.js.map +1 -0
  24. package/dist/cli/notifier/versionCompare.d.ts +48 -0
  25. package/dist/cli/notifier/versionCompare.d.ts.map +1 -0
  26. package/dist/cli/notifier/versionCompare.js +89 -0
  27. package/dist/cli/notifier/versionCompare.js.map +1 -0
  28. package/dist/cli/runCli.d.ts +2 -0
  29. package/dist/cli/runCli.d.ts.map +1 -1
  30. package/dist/cli/runCli.js +36 -4
  31. package/dist/cli/runCli.js.map +1 -1
  32. package/dist/config/ignoreDependencies.d.ts +7 -0
  33. package/dist/config/ignoreDependencies.d.ts.map +1 -0
  34. package/dist/config/ignoreDependencies.js +18 -0
  35. package/dist/config/ignoreDependencies.js.map +1 -0
  36. package/dist/config/ignorePaths.d.ts +13 -0
  37. package/dist/config/ignorePaths.d.ts.map +1 -0
  38. package/dist/config/ignorePaths.js +47 -0
  39. package/dist/config/ignorePaths.js.map +1 -0
  40. package/dist/config/projectConfigError.d.ts +7 -0
  41. package/dist/config/projectConfigError.d.ts.map +1 -0
  42. package/dist/config/projectConfigError.js +10 -0
  43. package/dist/config/projectConfigError.js.map +1 -0
  44. package/dist/config/readProjectConfig.d.ts +23 -0
  45. package/dist/config/readProjectConfig.d.ts.map +1 -0
  46. package/dist/config/readProjectConfig.js +106 -0
  47. package/dist/config/readProjectConfig.js.map +1 -0
  48. package/dist/core/analyzeProject.d.ts +48 -6
  49. package/dist/core/analyzeProject.d.ts.map +1 -1
  50. package/dist/core/analyzeProject.js +123 -16
  51. package/dist/core/analyzeProject.js.map +1 -1
  52. package/dist/detectors/eslintManifestConfig.d.ts +111 -0
  53. package/dist/detectors/eslintManifestConfig.d.ts.map +1 -0
  54. package/dist/detectors/eslintManifestConfig.js +351 -0
  55. package/dist/detectors/eslintManifestConfig.js.map +1 -0
  56. package/dist/detectors/eslintRcJsonConfig.d.ts +85 -0
  57. package/dist/detectors/eslintRcJsonConfig.d.ts.map +1 -0
  58. package/dist/detectors/eslintRcJsonConfig.js +189 -0
  59. package/dist/detectors/eslintRcJsonConfig.js.map +1 -0
  60. package/dist/detectors/jestManifestConfig.d.ts +76 -0
  61. package/dist/detectors/jestManifestConfig.d.ts.map +1 -0
  62. package/dist/detectors/jestManifestConfig.js +294 -0
  63. package/dist/detectors/jestManifestConfig.js.map +1 -0
  64. package/dist/reporters/terminalReporter.js +27 -1
  65. package/dist/reporters/terminalReporter.js.map +1 -1
  66. package/dist/scanner/moduleSpecifiers.d.ts +9 -1
  67. package/dist/scanner/moduleSpecifiers.d.ts.map +1 -1
  68. package/dist/scanner/moduleSpecifiers.js +3317 -205
  69. package/dist/scanner/moduleSpecifiers.js.map +1 -1
  70. package/dist/scanner/packageSpecifier.d.ts +26 -2
  71. package/dist/scanner/packageSpecifier.d.ts.map +1 -1
  72. package/dist/scanner/packageSpecifier.js +70 -2
  73. package/dist/scanner/packageSpecifier.js.map +1 -1
  74. package/dist/scanner/projectManifest.d.ts +31 -1
  75. package/dist/scanner/projectManifest.d.ts.map +1 -1
  76. package/dist/scanner/projectManifest.js +83 -4
  77. package/dist/scanner/projectManifest.js.map +1 -1
  78. package/dist/scanner/scriptUsage.d.ts +2 -1
  79. package/dist/scanner/scriptUsage.d.ts.map +1 -1
  80. package/dist/scanner/scriptUsage.js +216 -39
  81. package/dist/scanner/scriptUsage.js.map +1 -1
  82. package/dist/scanner/sourceFiles.d.ts +16 -2
  83. package/dist/scanner/sourceFiles.d.ts.map +1 -1
  84. package/dist/scanner/sourceFiles.js +12 -6
  85. package/dist/scanner/sourceFiles.js.map +1 -1
  86. package/package.json +7 -7
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Pure version comparison for the optional CLI update notifier.
3
+ *
4
+ * The notifier may only point an interactive user at a strictly newer *stable* DepVitals release,
5
+ * so the ordering rule here is intentionally bounded to `major.minor.patch` with decimal digits.
6
+ * Full semver ordering (prerelease precedence such as `-rc.1` < `-rc.2`, numeric-vs-alphanumeric
7
+ * identifiers, build metadata significance) is deliberately **not** implemented: the update-notifier
8
+ * contract requires skipping the notification for such versions instead of inventing an unreliable
9
+ * comparison, so every prerelease or build-tagged version is rejected conservatively.
10
+ *
11
+ * The module is pure by design: no filesystem, no network, no environment, no cache, no output and
12
+ * no `semver` dependency. Untrusted strings are validated by strict pattern matching, never parsed
13
+ * leniently, and no input can make these functions throw.
14
+ *
15
+ * This helper performs no eligibility decision and activates nothing; callers (later notifier code)
16
+ * decide whether a lookup happened and whether the notice may be printed.
17
+ */
18
+ /** A parsed stable version; tuple order is `major`, `minor`, `patch`. */
19
+ type ParsedVersion = readonly [major: number, minor: number, patch: number];
20
+ /**
21
+ * Parses an exact `major.minor.patch` string.
22
+ *
23
+ * Returns `undefined` for a `v` prefix, empty input, whitespace, missing or extra components
24
+ * (`0.2`, `1.2.3.4`), prerelease tags (`0.2.0-rc.1`), build metadata (`1.2.3+build.5`), partial
25
+ * tokens (`1.x.3`), leading zeros (`01.2.3`) and any other malformed metadata.
26
+ *
27
+ * Exported for the notifier's own consumers (Step 66 validates untrusted registry text with this
28
+ * single grammar) so exactly one place defines what "an exact stable DepVitals version" means.
29
+ */
30
+ export declare function parseStableVersion(value: string): ParsedVersion | undefined;
31
+ /**
32
+ * Reports whether a registry `latest` version is strictly newer than the installed DepVitals
33
+ * version, using numeric comparison in `major`, `minor`, `patch` order (never string ordering, so
34
+ * `0.2.10` is newer than `0.2.9`).
35
+ *
36
+ * Returns `false` — never a notification — when the versions are equal, when `latest` is older, or
37
+ * when either input is not an exact stable version. That includes a prerelease installed build
38
+ * (e.g. a local `0.2.0-rc.1`), which silently skips notification rather than relying on ordering
39
+ * this helper does not implement.
40
+ *
41
+ * @param current - The installed DepVitals CLI version; callers must validate untrusted strings
42
+ * (for example registry JSON) before passing them here.
43
+ * @param latest - The `latest` dist-tag reported for the package.
44
+ * @returns `true` only for a strictly newer stable `latest`; `false` for everything else.
45
+ */
46
+ export declare function isNewerStableVersion(current: string, latest: string): boolean;
47
+ export {};
48
+ //# sourceMappingURL=versionCompare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versionCompare.d.ts","sourceRoot":"","sources":["../../../src/cli/notifier/versionCompare.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH,yEAAyE;AACzE,KAAK,aAAa,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAiB5E;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAgB3E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAoB7E"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Pure version comparison for the optional CLI update notifier.
3
+ *
4
+ * The notifier may only point an interactive user at a strictly newer *stable* DepVitals release,
5
+ * so the ordering rule here is intentionally bounded to `major.minor.patch` with decimal digits.
6
+ * Full semver ordering (prerelease precedence such as `-rc.1` < `-rc.2`, numeric-vs-alphanumeric
7
+ * identifiers, build metadata significance) is deliberately **not** implemented: the update-notifier
8
+ * contract requires skipping the notification for such versions instead of inventing an unreliable
9
+ * comparison, so every prerelease or build-tagged version is rejected conservatively.
10
+ *
11
+ * The module is pure by design: no filesystem, no network, no environment, no cache, no output and
12
+ * no `semver` dependency. Untrusted strings are validated by strict pattern matching, never parsed
13
+ * leniently, and no input can make these functions throw.
14
+ *
15
+ * This helper performs no eligibility decision and activates nothing; callers (later notifier code)
16
+ * decide whether a lookup happened and whether the notice may be printed.
17
+ */
18
+ /**
19
+ * One strictly numeric version component: no sign, no whitespace, no exponent, no leading zeros
20
+ * (padding is ambiguous and is not part of how npm publishes stable versions).
21
+ */
22
+ const COMPONENT = /^(?:0|[1-9][0-9]*)$/;
23
+ /**
24
+ * Parses one numeric component, returning `undefined` when it is not strictly numeric or when its
25
+ * value is not a safe integer (absurdly large digit strings must never be compared by floating-point
26
+ * rounding).
27
+ */
28
+ function parseComponent(value) {
29
+ if (value === undefined || !COMPONENT.test(value)) {
30
+ return undefined;
31
+ }
32
+ const parsed = Number.parseInt(value, 10);
33
+ return Number.isSafeInteger(parsed) ? parsed : undefined;
34
+ }
35
+ /**
36
+ * Parses an exact `major.minor.patch` string.
37
+ *
38
+ * Returns `undefined` for a `v` prefix, empty input, whitespace, missing or extra components
39
+ * (`0.2`, `1.2.3.4`), prerelease tags (`0.2.0-rc.1`), build metadata (`1.2.3+build.5`), partial
40
+ * tokens (`1.x.3`), leading zeros (`01.2.3`) and any other malformed metadata.
41
+ *
42
+ * Exported for the notifier's own consumers (Step 66 validates untrusted registry text with this
43
+ * single grammar) so exactly one place defines what "an exact stable DepVitals version" means.
44
+ */
45
+ export function parseStableVersion(value) {
46
+ const parts = value.split('.');
47
+ if (parts.length !== 3) {
48
+ return undefined;
49
+ }
50
+ const major = parseComponent(parts[0]);
51
+ const minor = parseComponent(parts[1]);
52
+ const patch = parseComponent(parts[2]);
53
+ if (major === undefined || minor === undefined || patch === undefined) {
54
+ return undefined;
55
+ }
56
+ return [major, minor, patch];
57
+ }
58
+ /**
59
+ * Reports whether a registry `latest` version is strictly newer than the installed DepVitals
60
+ * version, using numeric comparison in `major`, `minor`, `patch` order (never string ordering, so
61
+ * `0.2.10` is newer than `0.2.9`).
62
+ *
63
+ * Returns `false` — never a notification — when the versions are equal, when `latest` is older, or
64
+ * when either input is not an exact stable version. That includes a prerelease installed build
65
+ * (e.g. a local `0.2.0-rc.1`), which silently skips notification rather than relying on ordering
66
+ * this helper does not implement.
67
+ *
68
+ * @param current - The installed DepVitals CLI version; callers must validate untrusted strings
69
+ * (for example registry JSON) before passing them here.
70
+ * @param latest - The `latest` dist-tag reported for the package.
71
+ * @returns `true` only for a strictly newer stable `latest`; `false` for everything else.
72
+ */
73
+ export function isNewerStableVersion(current, latest) {
74
+ const installed = parseStableVersion(current);
75
+ const published = parseStableVersion(latest);
76
+ if (installed === undefined || published === undefined) {
77
+ return false;
78
+ }
79
+ const [installedMajor, installedMinor, installedPatch] = installed;
80
+ const [publishedMajor, publishedMinor, publishedPatch] = published;
81
+ if (publishedMajor !== installedMajor) {
82
+ return publishedMajor > installedMajor;
83
+ }
84
+ if (publishedMinor !== installedMinor) {
85
+ return publishedMinor > installedMinor;
86
+ }
87
+ return publishedPatch > installedPatch;
88
+ }
89
+ //# sourceMappingURL=versionCompare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versionCompare.js","sourceRoot":"","sources":["../../../src/cli/notifier/versionCompare.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;GAGG;AACH,MAAM,SAAS,GAAG,qBAAqB,CAAC;AAKxC;;;;GAIG;AACH,SAAS,cAAc,CAAC,KAAyB;IAC/C,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAE1C,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAE/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACtE,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe,EAAE,MAAc;IAClE,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE7C,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QACvD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,cAAc,EAAE,cAAc,EAAE,cAAc,CAAC,GAAG,SAAS,CAAC;IACnE,MAAM,CAAC,cAAc,EAAE,cAAc,EAAE,cAAc,CAAC,GAAG,SAAS,CAAC;IAEnE,IAAI,cAAc,KAAK,cAAc,EAAE,CAAC;QACtC,OAAO,cAAc,GAAG,cAAc,CAAC;IACzC,CAAC;IAED,IAAI,cAAc,KAAK,cAAc,EAAE,CAAC;QACtC,OAAO,cAAc,GAAG,cAAc,CAAC;IACzC,CAAC;IAED,OAAO,cAAc,GAAG,cAAc,CAAC;AACzC,CAAC"}
@@ -7,6 +7,8 @@
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;
10
12
  * - run the static dependency scan with `analyzeProject`;
11
13
  * - render the report with the pure terminal reporter;
12
14
  * - decide the scan exit code from `hasDependencyIssues`, not from the report string;
@@ -1 +1 @@
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"}
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"}
@@ -7,6 +7,8 @@
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;
10
12
  * - run the static dependency scan with `analyzeProject`;
11
13
  * - render the report with the pure terminal reporter;
12
14
  * - decide the scan exit code from `hasDependencyIssues`, not from the report string;
@@ -15,9 +17,13 @@
15
17
  * It deliberately does not implement any scanning or dependency-analysis logic: that stays in
16
18
  * `src/core`, and the reporter stays in `src/reporters`.
17
19
  */
20
+ import { readProjectConfig, ProjectConfigError } from '../config/readProjectConfig.js';
18
21
  import { AnalysisError, analyzeProject } from '../core/analyzeProject.js';
22
+ import { findEslintManifestUsage } from '../detectors/eslintManifestConfig.js';
23
+ import { EslintRcJsonError, findEslintRcJsonUsage } from '../detectors/eslintRcJsonConfig.js';
24
+ import { findJestManifestUsage } from '../detectors/jestManifestConfig.js';
19
25
  import { formatTerminalReport, hasDependencyIssues } from '../reporters/terminalReporter.js';
20
- import { ProjectManifestError } from '../scanner/projectManifest.js';
26
+ import { loadProjectManifest, ProjectManifestError } from '../scanner/projectManifest.js';
21
27
  import { SourceFilesError } from '../scanner/sourceFiles.js';
22
28
  import { parseCliArgs } from './parseCliArgs.js';
23
29
  const HELP_MESSAGE = [
@@ -65,7 +71,14 @@ export async function runCli(args, options) {
65
71
  async function runScan(projectPath) {
66
72
  let result;
67
73
  try {
68
- result = await analyzeProject(projectPath);
74
+ // Validate mandatory root metadata, then the selected-root policy, before detector reads.
75
+ await loadProjectManifest(projectPath);
76
+ const config = await readProjectConfig(projectPath);
77
+ // Legacy ESLint configuration contributes configuration-only names. They are passed through the
78
+ // analyzer's config handoff, which merges them into `usedNames` only, so they can suppress an
79
+ // unused finding and can never create a missing one.
80
+ const configUsedNames = await collectConfigUsedNames(projectPath);
81
+ result = await analyzeProject(projectPath, { ...config, configUsedNames });
69
82
  }
70
83
  catch (error) {
71
84
  if (isOperationalError(error)) {
@@ -80,14 +93,33 @@ async function runScan(projectPath) {
80
93
  const hasIssues = hasDependencyIssues(result);
81
94
  return { exitCode: hasIssues ? 1 : 0, stdout: formatTerminalReport(result), stderr: '' };
82
95
  }
96
+ /**
97
+ * Collect the configuration-only package names of one project.
98
+ *
99
+ * Both legacy ESLint sources share one precedence computation: a hard barrier disables both, and
100
+ * otherwise `.eslintrc.json` wins over the `package.json#eslintConfig` block, so the two readers are
101
+ * mutually exclusive and the union never combines contradictory configuration. The `package.json#jest`
102
+ * reader is independent of the ESLint rules but obeys the same style of guard, producing nothing once
103
+ * a root `jest.config.*` file exists. The analyzer re-validates and sorts the merged hints, so no
104
+ * ordering is imposed here.
105
+ */
106
+ async function collectConfigUsedNames(projectPath) {
107
+ const manifestNames = await findEslintManifestUsage(projectPath);
108
+ const eslintRcJsonNames = await findEslintRcJsonUsage(projectPath);
109
+ const jestNames = await findJestManifestUsage(projectPath);
110
+ return new Set([...manifestNames, ...eslintRcJsonNames, ...jestNames]);
111
+ }
83
112
  /**
84
113
  * 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.
114
+ * error classes plus configuration errors count; everything else is treated as an
115
+ * unexpected internal failure.
86
116
  */
87
117
  function isOperationalError(error) {
88
118
  return (error instanceof ProjectManifestError ||
89
119
  error instanceof SourceFilesError ||
90
- error instanceof AnalysisError);
120
+ error instanceof AnalysisError ||
121
+ error instanceof EslintRcJsonError ||
122
+ error instanceof ProjectConfigError);
91
123
  }
92
124
  /**
93
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":"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"}
@@ -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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"}
@@ -24,20 +24,27 @@
24
24
  * once and parsed once. No concurrency pool, cache or index is introduced before a measured need
25
25
  * appears.
26
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):
27
+ * Usage/missing formulas (`usedNames` is the union of source-external package roots, script-used
28
+ * package names and validated configuration-only package names; `declaredDependencyNames` is the
29
+ * union of every declared dependency section):
29
30
  *
30
31
  * ```text
31
32
  * sourceUsedNames = external package roots extracted from source files
32
33
  * scriptUsedNames = findPackageScriptUsage(scripts, dependencies ∪ devDependencies)
33
- * usedNames = sourceUsedNames ∪ scriptUsedNames
34
+ * configUsedNames = validated configuration-only names handed to the analyzer (empty for now)
35
+ * usedNames = sourceUsedNames ∪ scriptUsedNames ∪ configUsedNames
34
36
  * unusedDependencies = dependencies − usedNames
35
37
  * unusedDevDependencies = devDependencies − usedNames
36
38
  * missingDependencies = sourceUsedNames − declaredDependencyNames
37
39
  * ```
38
40
  *
39
- * Scripts never generate missing-dependency findings, and peer/optional declarations suppress false
40
- * missing results through `declaredDependencyNames`.
41
+ * The evidence sources are deliberately asymmetric:
42
+ * - source imports and requires may contribute to `missingDependencies`;
43
+ * - package scripts and validated static tool configuration may only suppress an unused finding and
44
+ * can never create a missing finding, because a command or configuration string is not evidence
45
+ * that source code references the package.
46
+ *
47
+ * Peer/optional declarations suppress false missing results through `declaredDependencyNames`.
41
48
  */
42
49
  /**
43
50
  * The structured outcome of a dependency analysis.
@@ -57,6 +64,39 @@ export type AnalysisResult = {
57
64
  /** External packages referenced by source but not declared anywhere, sorted alphabetically. */
58
65
  missingDependencies: readonly string[];
59
66
  };
67
+ /**
68
+ * Internal handoff for package names recognized by a validated static configuration reader.
69
+ *
70
+ * This is deliberately not the future public `why` evidence model: it carries no location, kind, or
71
+ * explanation, and it is never rendered or exposed. A configuration reader hands the package names it
72
+ * recognized to the analyzer through this set; only {@link analyzeProject} turns them into final
73
+ * unused/missing categories, so no configuration reader may edit report arrays directly.
74
+ *
75
+ * The analyzer validates every entry with {@link classifyPackageSpecifier} before using it, so
76
+ * arbitrary configuration text can never be treated as a package name. Accepted entries are collapsed
77
+ * to their package root and deduplicated case-sensitively, matching package-specifier classification
78
+ * (names are compared case-sensitively throughout DepVitals).
79
+ *
80
+ * The set may only suppress unused findings; it is never merged into the source-derived names that
81
+ * produce missing findings.
82
+ */
83
+ export type ConfigUsageHints = ReadonlySet<string>;
84
+ /**
85
+ * Optional inputs for {@link analyzeProject}.
86
+ */
87
+ export type AnalysisOptions = {
88
+ /**
89
+ * Validated configuration-only package names, see {@link ConfigUsageHints}.
90
+ *
91
+ * Omitted or empty is the default, which is the state of the released product: no configuration
92
+ * rule is active yet, so the default keeps every report byte-for-byte identical.
93
+ */
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;
99
+ };
60
100
  /**
61
101
  * Why the analysis could not complete.
62
102
  *
@@ -84,9 +124,11 @@ export declare class AnalysisError extends Error {
84
124
  * The supplied root is resolved to an absolute path; `process.cwd()` is never changed and the target
85
125
  * project is never written to.
86
126
  *
127
+ * @param projectRoot - Directory to analyze.
128
+ * @param options - Optional static tool hints and validated source exclusions; omitted inputs change nothing.
87
129
  * @throws {AnalysisError} when a discovered source file cannot be read or cannot be safely analyzed.
88
130
  * @throws {ProjectManifestError} when the manifest is missing, unreadable, invalid or malformed.
89
131
  * @throws {SourceFilesError} when the root is missing, is not a directory, or cannot be read.
90
132
  */
91
- export declare function analyzeProject(projectRoot: string): Promise<AnalysisResult>;
133
+ export declare function analyzeProject(projectRoot: string, options?: AnalysisOptions): Promise<AnalysisResult>;
92
134
  //# sourceMappingURL=analyzeProject.d.ts.map