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.
Files changed (40) hide show
  1. package/README.md +67 -10
  2. package/dist/cli/index.js +13 -7
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/cli/parseCliArgs.d.ts +37 -0
  5. package/dist/cli/parseCliArgs.d.ts.map +1 -0
  6. package/dist/cli/parseCliArgs.js +85 -0
  7. package/dist/cli/parseCliArgs.js.map +1 -0
  8. package/dist/cli/runCli.d.ts +31 -13
  9. package/dist/cli/runCli.d.ts.map +1 -1
  10. package/dist/cli/runCli.js +76 -84
  11. package/dist/cli/runCli.js.map +1 -1
  12. package/dist/core/analyzeProject.d.ts +92 -0
  13. package/dist/core/analyzeProject.d.ts.map +1 -0
  14. package/dist/core/analyzeProject.js +175 -0
  15. package/dist/core/analyzeProject.js.map +1 -0
  16. package/dist/reporters/terminalReporter.d.ts +49 -0
  17. package/dist/reporters/terminalReporter.d.ts.map +1 -0
  18. package/dist/reporters/terminalReporter.js +98 -0
  19. package/dist/reporters/terminalReporter.js.map +1 -0
  20. package/dist/scanner/moduleSpecifiers.d.ts +60 -0
  21. package/dist/scanner/moduleSpecifiers.d.ts.map +1 -0
  22. package/dist/scanner/moduleSpecifiers.js +824 -0
  23. package/dist/scanner/moduleSpecifiers.js.map +1 -0
  24. package/dist/scanner/packageSpecifier.d.ts +45 -0
  25. package/dist/scanner/packageSpecifier.d.ts.map +1 -0
  26. package/dist/scanner/packageSpecifier.js +98 -0
  27. package/dist/scanner/packageSpecifier.js.map +1 -0
  28. package/dist/scanner/projectManifest.d.ts +72 -0
  29. package/dist/scanner/projectManifest.d.ts.map +1 -0
  30. package/dist/scanner/projectManifest.js +176 -0
  31. package/dist/scanner/projectManifest.js.map +1 -0
  32. package/dist/scanner/scriptUsage.d.ts +54 -0
  33. package/dist/scanner/scriptUsage.d.ts.map +1 -0
  34. package/dist/scanner/scriptUsage.js +490 -0
  35. package/dist/scanner/scriptUsage.js.map +1 -0
  36. package/dist/scanner/sourceFiles.d.ts +52 -0
  37. package/dist/scanner/sourceFiles.d.ts.map +1 -0
  38. package/dist/scanner/sourceFiles.js +190 -0
  39. package/dist/scanner/sourceFiles.js.map +1 -0
  40. 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.0.1",
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
  ],