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.
- package/README.md +39 -61
- package/dist/cli/entry.d.ts +59 -0
- package/dist/cli/entry.d.ts.map +1 -0
- package/dist/cli/entry.js +95 -0
- package/dist/cli/entry.js.map +1 -0
- package/dist/cli/index.js +14 -18
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/notifier/eligibility.d.ts +65 -0
- package/dist/cli/notifier/eligibility.d.ts.map +1 -0
- package/dist/cli/notifier/eligibility.js +123 -0
- package/dist/cli/notifier/eligibility.js.map +1 -0
- package/dist/cli/notifier/registryLookup.d.ts +111 -0
- package/dist/cli/notifier/registryLookup.d.ts.map +1 -0
- package/dist/cli/notifier/registryLookup.js +211 -0
- package/dist/cli/notifier/registryLookup.js.map +1 -0
- package/dist/cli/notifier/updateCache.d.ts +101 -0
- package/dist/cli/notifier/updateCache.d.ts.map +1 -0
- package/dist/cli/notifier/updateCache.js +352 -0
- package/dist/cli/notifier/updateCache.js.map +1 -0
- package/dist/cli/notifier/updateCheck.d.ts +88 -0
- package/dist/cli/notifier/updateCheck.d.ts.map +1 -0
- package/dist/cli/notifier/updateCheck.js +166 -0
- package/dist/cli/notifier/updateCheck.js.map +1 -0
- package/dist/cli/notifier/versionCompare.d.ts +48 -0
- package/dist/cli/notifier/versionCompare.d.ts.map +1 -0
- package/dist/cli/notifier/versionCompare.js +89 -0
- package/dist/cli/notifier/versionCompare.js.map +1 -0
- package/dist/cli/runCli.d.ts +2 -0
- package/dist/cli/runCli.d.ts.map +1 -1
- package/dist/cli/runCli.js +36 -4
- package/dist/cli/runCli.js.map +1 -1
- package/dist/config/ignoreDependencies.d.ts +7 -0
- package/dist/config/ignoreDependencies.d.ts.map +1 -0
- package/dist/config/ignoreDependencies.js +18 -0
- package/dist/config/ignoreDependencies.js.map +1 -0
- package/dist/config/ignorePaths.d.ts +13 -0
- package/dist/config/ignorePaths.d.ts.map +1 -0
- package/dist/config/ignorePaths.js +47 -0
- package/dist/config/ignorePaths.js.map +1 -0
- package/dist/config/projectConfigError.d.ts +7 -0
- package/dist/config/projectConfigError.d.ts.map +1 -0
- package/dist/config/projectConfigError.js +10 -0
- package/dist/config/projectConfigError.js.map +1 -0
- package/dist/config/readProjectConfig.d.ts +23 -0
- package/dist/config/readProjectConfig.d.ts.map +1 -0
- package/dist/config/readProjectConfig.js +106 -0
- package/dist/config/readProjectConfig.js.map +1 -0
- package/dist/core/analyzeProject.d.ts +48 -6
- package/dist/core/analyzeProject.d.ts.map +1 -1
- package/dist/core/analyzeProject.js +123 -16
- package/dist/core/analyzeProject.js.map +1 -1
- package/dist/detectors/eslintManifestConfig.d.ts +111 -0
- package/dist/detectors/eslintManifestConfig.d.ts.map +1 -0
- package/dist/detectors/eslintManifestConfig.js +351 -0
- package/dist/detectors/eslintManifestConfig.js.map +1 -0
- package/dist/detectors/eslintRcJsonConfig.d.ts +85 -0
- package/dist/detectors/eslintRcJsonConfig.d.ts.map +1 -0
- package/dist/detectors/eslintRcJsonConfig.js +189 -0
- package/dist/detectors/eslintRcJsonConfig.js.map +1 -0
- package/dist/detectors/jestManifestConfig.d.ts +76 -0
- package/dist/detectors/jestManifestConfig.d.ts.map +1 -0
- package/dist/detectors/jestManifestConfig.js +294 -0
- package/dist/detectors/jestManifestConfig.js.map +1 -0
- package/dist/reporters/terminalReporter.js +27 -1
- package/dist/reporters/terminalReporter.js.map +1 -1
- package/dist/scanner/moduleSpecifiers.d.ts +9 -1
- package/dist/scanner/moduleSpecifiers.d.ts.map +1 -1
- package/dist/scanner/moduleSpecifiers.js +3317 -205
- package/dist/scanner/moduleSpecifiers.js.map +1 -1
- package/dist/scanner/packageSpecifier.d.ts +26 -2
- package/dist/scanner/packageSpecifier.d.ts.map +1 -1
- package/dist/scanner/packageSpecifier.js +70 -2
- package/dist/scanner/packageSpecifier.js.map +1 -1
- package/dist/scanner/projectManifest.d.ts +31 -1
- package/dist/scanner/projectManifest.d.ts.map +1 -1
- package/dist/scanner/projectManifest.js +83 -4
- package/dist/scanner/projectManifest.js.map +1 -1
- package/dist/scanner/scriptUsage.d.ts +2 -1
- package/dist/scanner/scriptUsage.d.ts.map +1 -1
- package/dist/scanner/scriptUsage.js +216 -39
- package/dist/scanner/scriptUsage.js.map +1 -1
- package/dist/scanner/sourceFiles.d.ts +16 -2
- package/dist/scanner/sourceFiles.d.ts.map +1 -1
- package/dist/scanner/sourceFiles.js +12 -6
- package/dist/scanner/sourceFiles.js.map +1 -1
- 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"}
|
package/dist/cli/runCli.d.ts
CHANGED
|
@@ -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;
|
package/dist/cli/runCli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runCli.d.ts","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"runCli.d.ts","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;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"}
|
package/dist/cli/runCli.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
package/dist/cli/runCli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runCli.js","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"runCli.js","sourceRoot":"","sources":["../../src/cli/runCli.ts"],"names":[],"mappings":"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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"}
|
|
@@ -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
|
|
28
|
-
* package names; `declaredDependencyNames` is the
|
|
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
|
-
*
|
|
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
|
-
*
|
|
40
|
-
*
|
|
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
|