depvitals 0.0.1 → 0.1.1
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 +67 -10
- package/dist/cli/index.js +13 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/parseCliArgs.d.ts +37 -0
- package/dist/cli/parseCliArgs.d.ts.map +1 -0
- package/dist/cli/parseCliArgs.js +85 -0
- package/dist/cli/parseCliArgs.js.map +1 -0
- package/dist/cli/runCli.d.ts +31 -13
- package/dist/cli/runCli.d.ts.map +1 -1
- package/dist/cli/runCli.js +76 -84
- package/dist/cli/runCli.js.map +1 -1
- package/dist/core/analyzeProject.d.ts +92 -0
- package/dist/core/analyzeProject.d.ts.map +1 -0
- package/dist/core/analyzeProject.js +175 -0
- package/dist/core/analyzeProject.js.map +1 -0
- package/dist/reporters/terminalReporter.d.ts +49 -0
- package/dist/reporters/terminalReporter.d.ts.map +1 -0
- package/dist/reporters/terminalReporter.js +98 -0
- package/dist/reporters/terminalReporter.js.map +1 -0
- package/dist/scanner/moduleSpecifiers.d.ts +60 -0
- package/dist/scanner/moduleSpecifiers.d.ts.map +1 -0
- package/dist/scanner/moduleSpecifiers.js +824 -0
- package/dist/scanner/moduleSpecifiers.js.map +1 -0
- package/dist/scanner/packageSpecifier.d.ts +45 -0
- package/dist/scanner/packageSpecifier.d.ts.map +1 -0
- package/dist/scanner/packageSpecifier.js +98 -0
- package/dist/scanner/packageSpecifier.js.map +1 -0
- package/dist/scanner/projectManifest.d.ts +72 -0
- package/dist/scanner/projectManifest.d.ts.map +1 -0
- package/dist/scanner/projectManifest.js +176 -0
- package/dist/scanner/projectManifest.js.map +1 -0
- package/dist/scanner/scriptUsage.d.ts +54 -0
- package/dist/scanner/scriptUsage.d.ts.map +1 -0
- package/dist/scanner/scriptUsage.js +490 -0
- package/dist/scanner/scriptUsage.js.map +1 -0
- package/dist/scanner/sourceFiles.d.ts +52 -0
- package/dist/scanner/sourceFiles.d.ts.map +1 -0
- package/dist/scanner/sourceFiles.js +190 -0
- package/dist/scanner/sourceFiles.js.map +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source file discovery.
|
|
3
|
+
*
|
|
4
|
+
* This module answers exactly one question: "which source files should DepVitals inspect?". It
|
|
5
|
+
* walks a single Node.js project tree and returns the supported JavaScript/TypeScript files without
|
|
6
|
+
* parsing them.
|
|
7
|
+
*
|
|
8
|
+
* It deliberately does not:
|
|
9
|
+
* - read, parse or execute any discovered file (that belongs to the analyzers / specifier extractor);
|
|
10
|
+
* - decide whether anything is used, unused or missing;
|
|
11
|
+
* - parse `.gitignore` or honor custom ignore configuration (`v0.1.0` uses a fixed built-in set);
|
|
12
|
+
* - follow symlinks, which avoids cycles and scanning content outside the intended project tree;
|
|
13
|
+
* - mutate the analyzed project.
|
|
14
|
+
*
|
|
15
|
+
* Traversal uses `fs.readdir` with `withFileTypes` so ignored directories are pruned before descent
|
|
16
|
+
* instead of walking every subtree and filtering afterwards. The result is sorted deterministically
|
|
17
|
+
* so the same tree always yields the same order.
|
|
18
|
+
*/
|
|
19
|
+
import { lstat, readdir } from 'node:fs/promises';
|
|
20
|
+
import { extname, join, resolve } from 'node:path';
|
|
21
|
+
/**
|
|
22
|
+
* The supported source and declaration extensions for `v0.1.0`.
|
|
23
|
+
*
|
|
24
|
+
* Multi-part declaration files are included through their base extension:
|
|
25
|
+
* - `foo.d.ts` resolves to `.ts`
|
|
26
|
+
* - `foo.d.mts` resolves to `.mts`
|
|
27
|
+
* - `foo.d.cts` resolves to `.cts`
|
|
28
|
+
*
|
|
29
|
+
* The rule that matters is only "never exclude a name because it starts with `.d`".
|
|
30
|
+
*/
|
|
31
|
+
const SUPPORTED_EXTENSIONS = new Set([
|
|
32
|
+
'.js',
|
|
33
|
+
'.jsx',
|
|
34
|
+
'.mjs',
|
|
35
|
+
'.cjs',
|
|
36
|
+
'.ts',
|
|
37
|
+
'.tsx',
|
|
38
|
+
'.mts',
|
|
39
|
+
'.cts',
|
|
40
|
+
]);
|
|
41
|
+
/**
|
|
42
|
+
* Directories pruned by name wherever they appear. These are generated, vendor or tooling trees
|
|
43
|
+
* that must never be enumerated (in particular `node_modules`).
|
|
44
|
+
*/
|
|
45
|
+
const IGNORED_DIRECTORY_NAMES = new Set([
|
|
46
|
+
'.git',
|
|
47
|
+
'node_modules',
|
|
48
|
+
'dist',
|
|
49
|
+
'build',
|
|
50
|
+
'coverage',
|
|
51
|
+
'out',
|
|
52
|
+
'.cache',
|
|
53
|
+
'.turbo',
|
|
54
|
+
'.next',
|
|
55
|
+
'.nuxt',
|
|
56
|
+
]);
|
|
57
|
+
/**
|
|
58
|
+
* Operational error for source discovery. The `code` lets callers (the CLI in a later step) render
|
|
59
|
+
* a clean message without matching on error strings.
|
|
60
|
+
*/
|
|
61
|
+
export class SourceFilesError extends Error {
|
|
62
|
+
code;
|
|
63
|
+
constructor(message, code, cause) {
|
|
64
|
+
super(message, cause === undefined ? undefined : { cause });
|
|
65
|
+
this.name = 'SourceFilesError';
|
|
66
|
+
this.code = code;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Discover the supported JavaScript/TypeScript source files of the project rooted at `projectRoot`.
|
|
71
|
+
*
|
|
72
|
+
* The supplied root is resolved to an absolute path; `process.cwd()` is never changed and the
|
|
73
|
+
* target project is never read as code or written to.
|
|
74
|
+
*
|
|
75
|
+
* The returned paths are absolute and sorted lexicographically so the same tree always yields the
|
|
76
|
+
* same order.
|
|
77
|
+
*
|
|
78
|
+
* @throws {SourceFilesError} when the root is missing, is not a directory, or cannot be read.
|
|
79
|
+
*/
|
|
80
|
+
export async function discoverSourceFiles(projectRoot) {
|
|
81
|
+
const root = resolve(projectRoot);
|
|
82
|
+
await assertReadableRoot(root);
|
|
83
|
+
const files = [];
|
|
84
|
+
await walk(root, files);
|
|
85
|
+
// Sort the final result so the contract is explicitly deterministic regardless of filesystem
|
|
86
|
+
// enumeration order.
|
|
87
|
+
files.sort(comparePaths);
|
|
88
|
+
return files;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Validate that the resolved root exists and is a directory before walking it. A missing root is
|
|
92
|
+
* reported separately from a root that is a regular file, and any other I/O failure stays
|
|
93
|
+
* `unreadable`.
|
|
94
|
+
*
|
|
95
|
+
* `lstat` (not `stat`) is used on purpose: it does not follow a symlink supplied as the root, so a
|
|
96
|
+
* symlinked root is rejected instead of being traversed, keeping the "never follow symlinks"
|
|
97
|
+
* contract consistent from the entry point down.
|
|
98
|
+
*/
|
|
99
|
+
async function assertReadableRoot(root) {
|
|
100
|
+
try {
|
|
101
|
+
const info = await lstat(root);
|
|
102
|
+
if (info.isSymbolicLink()) {
|
|
103
|
+
throw new SourceFilesError(`Project root ${root} is a symlink and will not be followed`, 'not-a-directory');
|
|
104
|
+
}
|
|
105
|
+
if (!info.isDirectory()) {
|
|
106
|
+
throw new SourceFilesError(`Project root ${root} exists but is not a directory`, 'not-a-directory');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (error instanceof SourceFilesError) {
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
throw toReadError(root, error);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Recursively collect supported files under `directory`, pruning ignored directories and skipping
|
|
118
|
+
* symlinks before descending.
|
|
119
|
+
*/
|
|
120
|
+
async function walk(directory, files) {
|
|
121
|
+
let entries;
|
|
122
|
+
try {
|
|
123
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
throw new SourceFilesError(`Could not read directory ${directory}: ${messageOf(error)}`, 'unreadable', error);
|
|
127
|
+
}
|
|
128
|
+
for (const entry of entries) {
|
|
129
|
+
// Never follow symlinks: this avoids cycles, duplicates and escaping the project tree.
|
|
130
|
+
if (entry.isSymbolicLink()) {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const fullPath = join(directory, entry.name);
|
|
134
|
+
if (entry.isDirectory()) {
|
|
135
|
+
if (IGNORED_DIRECTORY_NAMES.has(entry.name)) {
|
|
136
|
+
// Prune before descending so trees like `node_modules` are never enumerated.
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
await walk(fullPath, files);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (entry.isFile() && isSupportedFile(entry.name)) {
|
|
143
|
+
files.push(fullPath);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Whether a file name has a supported source extension.
|
|
149
|
+
*/
|
|
150
|
+
function isSupportedFile(fileName) {
|
|
151
|
+
return SUPPORTED_EXTENSIONS.has(extname(fileName));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Classify a filesystem failure while validating the root: a missing root is expected and reported
|
|
155
|
+
* separately from any other I/O problem.
|
|
156
|
+
*/
|
|
157
|
+
function toReadError(root, error) {
|
|
158
|
+
if (isNotFoundError(error)) {
|
|
159
|
+
return new SourceFilesError(`Project root ${root} does not exist`, 'missing', error);
|
|
160
|
+
}
|
|
161
|
+
return new SourceFilesError(`Could not read project root ${root}: ${messageOf(error)}`, 'unreadable', error);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* A short, human-readable reason extracted from an unknown thrown value, for error messages only.
|
|
165
|
+
*/
|
|
166
|
+
function messageOf(error) {
|
|
167
|
+
if (error instanceof Error) {
|
|
168
|
+
return error.message;
|
|
169
|
+
}
|
|
170
|
+
return String(error);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Whether an unknown thrown value is the filesystem `ENOENT` error.
|
|
174
|
+
*/
|
|
175
|
+
function isNotFoundError(error) {
|
|
176
|
+
return error instanceof Error && 'code' in error && error.code === 'ENOENT';
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Locale-independent lexicographic ordering, so the same tree always yields the same order.
|
|
180
|
+
*/
|
|
181
|
+
function comparePaths(a, b) {
|
|
182
|
+
if (a < b) {
|
|
183
|
+
return -1;
|
|
184
|
+
}
|
|
185
|
+
if (a > b) {
|
|
186
|
+
return 1;
|
|
187
|
+
}
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=sourceFiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sourceFiles.js","sourceRoot":"","sources":["../../src/scanner/sourceFiles.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "depvitals",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "A simple, lightweight dependency health checker for Node.js projects.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nodejs",
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
"dependency-analysis",
|
|
10
10
|
"dependency-checker",
|
|
11
11
|
"dependency-health",
|
|
12
|
+
"unused-dependencies",
|
|
13
|
+
"missing-dependencies",
|
|
12
14
|
"depcheck",
|
|
13
15
|
"cli"
|
|
14
16
|
],
|