depvitals 0.1.1 → 0.2.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 +37 -54
- 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 +30 -3
- package/dist/cli/runCli.js.map +1 -1
- package/dist/core/analyzeProject.d.ts +44 -6
- package/dist/core/analyzeProject.d.ts.map +1 -1
- package/dist/core/analyzeProject.js +110 -11
- 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 +348 -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 +188 -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 +292 -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 +2352 -173
- package/dist/scanner/moduleSpecifiers.js.map +1 -1
- package/dist/scanner/projectManifest.d.ts +14 -0
- package/dist/scanner/projectManifest.d.ts.map +1 -1
- package/dist/scanner/projectManifest.js +40 -0
- package/dist/scanner/projectManifest.js.map +1 -1
- package/dist/scanner/scriptUsage.d.ts +11 -5
- package/dist/scanner/scriptUsage.d.ts.map +1 -1
- package/dist/scanner/scriptUsage.js +320 -16
- package/dist/scanner/scriptUsage.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;AAYH;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAkBF;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAa7F"}
|
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;
|
|
@@ -16,6 +18,9 @@
|
|
|
16
18
|
* `src/core`, and the reporter stays in `src/reporters`.
|
|
17
19
|
*/
|
|
18
20
|
import { AnalysisError, analyzeProject } from '../core/analyzeProject.js';
|
|
21
|
+
import { findEslintManifestUsage } from '../detectors/eslintManifestConfig.js';
|
|
22
|
+
import { EslintRcJsonError, findEslintRcJsonUsage } from '../detectors/eslintRcJsonConfig.js';
|
|
23
|
+
import { findJestManifestUsage } from '../detectors/jestManifestConfig.js';
|
|
19
24
|
import { formatTerminalReport, hasDependencyIssues } from '../reporters/terminalReporter.js';
|
|
20
25
|
import { ProjectManifestError } from '../scanner/projectManifest.js';
|
|
21
26
|
import { SourceFilesError } from '../scanner/sourceFiles.js';
|
|
@@ -65,7 +70,11 @@ export async function runCli(args, options) {
|
|
|
65
70
|
async function runScan(projectPath) {
|
|
66
71
|
let result;
|
|
67
72
|
try {
|
|
68
|
-
|
|
73
|
+
// Legacy ESLint configuration contributes configuration-only names. They are passed through the
|
|
74
|
+
// analyzer's config handoff, which merges them into `usedNames` only, so they can suppress an
|
|
75
|
+
// unused finding and can never create a missing one.
|
|
76
|
+
const configUsedNames = await collectConfigUsedNames(projectPath);
|
|
77
|
+
result = await analyzeProject(projectPath, { configUsedNames });
|
|
69
78
|
}
|
|
70
79
|
catch (error) {
|
|
71
80
|
if (isOperationalError(error)) {
|
|
@@ -80,14 +89,32 @@ async function runScan(projectPath) {
|
|
|
80
89
|
const hasIssues = hasDependencyIssues(result);
|
|
81
90
|
return { exitCode: hasIssues ? 1 : 0, stdout: formatTerminalReport(result), stderr: '' };
|
|
82
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Collect the configuration-only package names of one project.
|
|
94
|
+
*
|
|
95
|
+
* Both legacy ESLint sources share one precedence computation: a hard barrier disables both, and
|
|
96
|
+
* otherwise `.eslintrc.json` wins over the `package.json#eslintConfig` block, so the two readers are
|
|
97
|
+
* mutually exclusive and the union never combines contradictory configuration. The `package.json#jest`
|
|
98
|
+
* reader is independent of the ESLint rules but obeys the same style of guard, producing nothing once
|
|
99
|
+
* a root `jest.config.*` file exists. The analyzer re-validates and sorts the merged hints, so no
|
|
100
|
+
* ordering is imposed here.
|
|
101
|
+
*/
|
|
102
|
+
async function collectConfigUsedNames(projectPath) {
|
|
103
|
+
const manifestNames = await findEslintManifestUsage(projectPath);
|
|
104
|
+
const eslintRcJsonNames = await findEslintRcJsonUsage(projectPath);
|
|
105
|
+
const jestNames = await findJestManifestUsage(projectPath);
|
|
106
|
+
return new Set([...manifestNames, ...eslintRcJsonNames, ...jestNames]);
|
|
107
|
+
}
|
|
83
108
|
/**
|
|
84
109
|
* 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
|
|
110
|
+
* error classes plus the unusable-`.eslintrc.json` error count; everything else is treated as an
|
|
111
|
+
* unexpected internal failure.
|
|
86
112
|
*/
|
|
87
113
|
function isOperationalError(error) {
|
|
88
114
|
return (error instanceof ProjectManifestError ||
|
|
89
115
|
error instanceof SourceFilesError ||
|
|
90
|
-
error instanceof AnalysisError
|
|
116
|
+
error instanceof AnalysisError ||
|
|
117
|
+
error instanceof EslintRcJsonError);
|
|
91
118
|
}
|
|
92
119
|
/**
|
|
93
120
|
* 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":"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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,35 @@ 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
|
+
};
|
|
60
96
|
/**
|
|
61
97
|
* Why the analysis could not complete.
|
|
62
98
|
*
|
|
@@ -84,9 +120,11 @@ export declare class AnalysisError extends Error {
|
|
|
84
120
|
* The supplied root is resolved to an absolute path; `process.cwd()` is never changed and the target
|
|
85
121
|
* project is never written to.
|
|
86
122
|
*
|
|
123
|
+
* @param projectRoot - Directory to analyze.
|
|
124
|
+
* @param options - Optional {@link ConfigUsageHints}; an omitted or empty set changes nothing.
|
|
87
125
|
* @throws {AnalysisError} when a discovered source file cannot be read or cannot be safely analyzed.
|
|
88
126
|
* @throws {ProjectManifestError} when the manifest is missing, unreadable, invalid or malformed.
|
|
89
127
|
* @throws {SourceFilesError} when the root is missing, is not a directory, or cannot be read.
|
|
90
128
|
*/
|
|
91
|
-
export declare function analyzeProject(projectRoot: string): Promise<AnalysisResult>;
|
|
129
|
+
export declare function analyzeProject(projectRoot: string, options?: AnalysisOptions): Promise<AnalysisResult>;
|
|
92
130
|
//# sourceMappingURL=analyzeProject.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzeProject.d.ts","sourceRoot":"","sources":["../../src/core/analyzeProject.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"analyzeProject.d.ts","sourceRoot":"","sources":["../../src/core/analyzeProject.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAWH;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,uDAAuD;IACvD,qBAAqB,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,+FAA+F;IAC/F,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,gBAAgB,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AAEnD;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CACzD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAEvE;;;;;;;GAOG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;gBAErB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,CAAC,EAAE,OAAO;CAKtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAqDzB"}
|
|
@@ -24,23 +24,31 @@
|
|
|
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
|
import { readFile } from 'node:fs/promises';
|
|
43
|
-
import {
|
|
50
|
+
import { dirname } from 'node:path';
|
|
51
|
+
import { loadPackageTypeHint, loadProjectManifest } from '../scanner/projectManifest.js';
|
|
44
52
|
import { discoverSourceFiles } from '../scanner/sourceFiles.js';
|
|
45
53
|
import { extractModuleSpecifiers } from '../scanner/moduleSpecifiers.js';
|
|
46
54
|
import { classifyPackageSpecifier } from '../scanner/packageSpecifier.js';
|
|
@@ -67,17 +75,23 @@ export class AnalysisError extends Error {
|
|
|
67
75
|
* The supplied root is resolved to an absolute path; `process.cwd()` is never changed and the target
|
|
68
76
|
* project is never written to.
|
|
69
77
|
*
|
|
78
|
+
* @param projectRoot - Directory to analyze.
|
|
79
|
+
* @param options - Optional {@link ConfigUsageHints}; an omitted or empty set changes nothing.
|
|
70
80
|
* @throws {AnalysisError} when a discovered source file cannot be read or cannot be safely analyzed.
|
|
71
81
|
* @throws {ProjectManifestError} when the manifest is missing, unreadable, invalid or malformed.
|
|
72
82
|
* @throws {SourceFilesError} when the root is missing, is not a directory, or cannot be read.
|
|
73
83
|
*/
|
|
74
|
-
export async function analyzeProject(projectRoot) {
|
|
84
|
+
export async function analyzeProject(projectRoot, options = {}) {
|
|
75
85
|
const manifest = await loadProjectManifest(projectRoot);
|
|
76
86
|
const sourceFiles = await discoverSourceFiles(manifest.root);
|
|
77
87
|
// External package roots referenced by source files, collapsed to their package root.
|
|
78
88
|
const sourceUsedNames = new Set();
|
|
89
|
+
const packageTypeByDirectory = new Map([
|
|
90
|
+
[manifest.root, manifest.packageType],
|
|
91
|
+
]);
|
|
79
92
|
for (const file of sourceFiles) {
|
|
80
|
-
const
|
|
93
|
+
const packageType = await packageTypeForFile(file, manifest.root, packageTypeByDirectory);
|
|
94
|
+
const specifiers = await readAndExtract(file, packageType);
|
|
81
95
|
for (const specifier of specifiers) {
|
|
82
96
|
const classified = classifyPackageSpecifier(specifier);
|
|
83
97
|
if (classified.kind === 'external') {
|
|
@@ -92,7 +106,10 @@ export async function analyzeProject(projectRoot) {
|
|
|
92
106
|
Object.keys(manifest.devDependencies),
|
|
93
107
|
]);
|
|
94
108
|
const scriptUsedNames = findPackageScriptUsage(manifest.scripts, declaredCandidates);
|
|
95
|
-
|
|
109
|
+
// Configuration evidence never reaches `sourceUsedNames`, which is the only input able to produce
|
|
110
|
+
// a missing finding; it can only make `usedNames` bigger and therefore suppress unused findings.
|
|
111
|
+
const configUsedNames = normalizeConfigHints(options.configUsedNames);
|
|
112
|
+
const usedNames = unionNames([[...sourceUsedNames], [...scriptUsedNames], [...configUsedNames]]);
|
|
96
113
|
const unusedDependencies = declaredMinus(Object.keys(manifest.dependencies), usedNames);
|
|
97
114
|
const unusedDevDependencies = declaredMinus(Object.keys(manifest.devDependencies), usedNames);
|
|
98
115
|
// An external root is missing only when it is absent from every declared dependency section.
|
|
@@ -105,6 +122,26 @@ export async function analyzeProject(projectRoot) {
|
|
|
105
122
|
missingDependencies,
|
|
106
123
|
};
|
|
107
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Resolve the nearest package scope for one discovered source file.
|
|
127
|
+
*
|
|
128
|
+
* An existing nested `package.json` starts a new scope even when it omits `type`; directories
|
|
129
|
+
* without one inherit their parent. Results are cached per directory for the rest of the scan.
|
|
130
|
+
*/
|
|
131
|
+
async function packageTypeForFile(file, projectRoot, cache) {
|
|
132
|
+
return packageTypeForDirectory(dirname(file), projectRoot, cache);
|
|
133
|
+
}
|
|
134
|
+
async function packageTypeForDirectory(directory, projectRoot, cache) {
|
|
135
|
+
if (cache.has(directory)) {
|
|
136
|
+
return cache.get(directory);
|
|
137
|
+
}
|
|
138
|
+
const hint = await loadPackageTypeHint(directory);
|
|
139
|
+
const packageType = hint === undefined
|
|
140
|
+
? await packageTypeForDirectory(dirname(directory), projectRoot, cache)
|
|
141
|
+
: hint.packageType;
|
|
142
|
+
cache.set(directory, packageType);
|
|
143
|
+
return packageType;
|
|
144
|
+
}
|
|
108
145
|
/**
|
|
109
146
|
* Read a discovered source file and extract its statically known specifiers.
|
|
110
147
|
*
|
|
@@ -113,7 +150,7 @@ export async function analyzeProject(projectRoot) {
|
|
|
113
150
|
* preserve the original error as `cause` and include the affected path, so a broken file never
|
|
114
151
|
* yields a partial result or a misleading "clean" analysis.
|
|
115
152
|
*/
|
|
116
|
-
async function readAndExtract(file) {
|
|
153
|
+
async function readAndExtract(file, packageType) {
|
|
117
154
|
let source;
|
|
118
155
|
try {
|
|
119
156
|
source = await readFile(file, 'utf8');
|
|
@@ -121,8 +158,32 @@ async function readAndExtract(file) {
|
|
|
121
158
|
catch (error) {
|
|
122
159
|
throw new AnalysisError(`Could not read source file ${file}: ${messageOf(error)}`, 'unreadable-source', error);
|
|
123
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* Determine the narrow Node source mode needed for top-level `await`.
|
|
163
|
+
*
|
|
164
|
+
* Explicit module extensions win over the package type. CommonJS extensions remain scripts even
|
|
165
|
+
* under a module package, while `.js` and `.ts` follow the nearest package scope's exact
|
|
166
|
+
* `type: "module"` declaration.
|
|
167
|
+
*/
|
|
168
|
+
function isModuleSource(file, packageType) {
|
|
169
|
+
const lower = file.toLowerCase();
|
|
170
|
+
if (lower.endsWith('.mjs') || lower.endsWith('.mts')) {
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
if (lower.endsWith('.cjs') || lower.endsWith('.cts')) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
return ((lower.endsWith('.js') ||
|
|
177
|
+
lower.endsWith('.jsx') ||
|
|
178
|
+
lower.endsWith('.ts') ||
|
|
179
|
+
lower.endsWith('.tsx')) &&
|
|
180
|
+
packageType === 'module');
|
|
181
|
+
}
|
|
124
182
|
try {
|
|
125
|
-
const occurrences = extractModuleSpecifiers(source
|
|
183
|
+
const occurrences = extractModuleSpecifiers(source, {
|
|
184
|
+
jsx: usesJsxSyntax(file, source),
|
|
185
|
+
module: isModuleSource(file, packageType),
|
|
186
|
+
});
|
|
126
187
|
return occurrences.map((occurrence) => occurrence.specifier);
|
|
127
188
|
}
|
|
128
189
|
catch (error) {
|
|
@@ -132,6 +193,44 @@ async function readAndExtract(file) {
|
|
|
132
193
|
throw error;
|
|
133
194
|
}
|
|
134
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Whether a discovered source file may contain JSX syntax.
|
|
198
|
+
*
|
|
199
|
+
* `.jsx` and `.tsx` always enable the extractor's bounded JSX mode. Plain JavaScript extensions
|
|
200
|
+
* (`.js`, `.mjs` and `.cjs`) enable it only when the source contains a JSX-like closing or
|
|
201
|
+
* self-closing tag. TypeScript extensions other than `.tsx` stay in plain mode, so a `.ts` type
|
|
202
|
+
* assertion (`<Foo>value`) is never mistaken for markup. Extension checks are case-insensitive.
|
|
203
|
+
*/
|
|
204
|
+
function usesJsxSyntax(file, source) {
|
|
205
|
+
const lower = file.toLowerCase();
|
|
206
|
+
if (lower.endsWith('.jsx') || lower.endsWith('.tsx')) {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
return /\.(?:js|mjs|cjs)$/.test(lower) && /<\/[A-Za-z]|\/>/.test(source);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Turn the internal configuration handoff into validated package roots.
|
|
213
|
+
*
|
|
214
|
+
* The entries come from configuration reading code, not from the trusted analyzer, so each one is
|
|
215
|
+
* re-validated with the same utility that classifies source specifiers. Builtins, relative or
|
|
216
|
+
* absolute paths, malformed scoped names, URIs, whitespace and version suffixes are dropped instead
|
|
217
|
+
* of being trusted as package names. Accepted entries collapse to their package root and are
|
|
218
|
+
* deduplicated case-sensitively; an omitted set behaves exactly like an empty one.
|
|
219
|
+
*/
|
|
220
|
+
function normalizeConfigHints(hints) {
|
|
221
|
+
const names = new Set();
|
|
222
|
+
if (hints === undefined) {
|
|
223
|
+
return names;
|
|
224
|
+
}
|
|
225
|
+
for (const hint of hints) {
|
|
226
|
+
const classified = classifyPackageSpecifier(hint);
|
|
227
|
+
if (classified.kind === 'external') {
|
|
228
|
+
names.add(classified.packageName);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Rebuilt from sorted names so iteration order never depends on the caller's set insertion order.
|
|
232
|
+
return new Set([...names].sort(compareNames));
|
|
233
|
+
}
|
|
135
234
|
/**
|
|
136
235
|
* Union of the names of every supplied list, sorted alphabetically.
|
|
137
236
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzeProject.js","sourceRoot":"","sources":["../../src/core/analyzeProject.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"analyzeProject.js","sourceRoot":"","sources":["../../src/core/analyzeProject.ts"],"names":[],"mappings":"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"}
|