dependency-radar 0.2.0 → 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 +176 -19
- package/dist/aggregator.js +1021 -406
- package/dist/cli.js +857 -56
- package/dist/generated/spdx.js +855 -0
- package/dist/license.js +324 -0
- package/dist/report-assets.js +2 -2
- package/dist/report.js +88 -89
- package/dist/runners/importGraphRunner.js +11 -5
- package/dist/runners/npmAudit.js +81 -16
- package/dist/runners/npmLs.js +216 -15
- package/dist/runners/npmOutdated.js +115 -0
- package/dist/utils.js +159 -24
- package/package.json +23 -3
package/README.md
CHANGED
|
@@ -17,6 +17,18 @@ Dependency Radar is a local-first CLI tool that inspects a Node.js project’s i
|
|
|
17
17
|
- Not a bundler or build tool
|
|
18
18
|
- Not a dependency updater
|
|
19
19
|
|
|
20
|
+
|
|
21
|
+
## License Scanning
|
|
22
|
+
|
|
23
|
+
Dependency Radar validates SPDX licenses declared in `package.json` and can infer licenses from `LICENSE` files when declarations are missing or invalid. It works offline and uses a bundled SPDX identifier list (generated at build time) with no runtime network access. Each dependency gets a structured license record with:
|
|
24
|
+
|
|
25
|
+
- Declared SPDX validation (including deprecated IDs and `WITH` exceptions)
|
|
26
|
+
- Inferred SPDX license (with confidence: `high`, `medium`, `low`) based on deterministic text matching
|
|
27
|
+
- A status (`declared-only`, `inferred-only`, `match`, `mismatch`, `invalid-spdx`, `unknown`) to make review decisions easier
|
|
28
|
+
|
|
29
|
+
This logic applies to all dependencies (direct and transitive). Inferred licenses are never treated as authoritative over valid declared SPDX expressions.
|
|
30
|
+
|
|
31
|
+
|
|
20
32
|
## Setup
|
|
21
33
|
|
|
22
34
|
```bash
|
|
@@ -53,10 +65,10 @@ Keep the temporary `.dependency-radar` folder for debugging raw tool outputs:
|
|
|
53
65
|
npx dependency-radar --keep-temp
|
|
54
66
|
```
|
|
55
67
|
|
|
56
|
-
Skip `npm audit` (useful for offline scans):
|
|
68
|
+
Skip `npm audit` and `npm outdated` (useful for offline scans):
|
|
57
69
|
|
|
58
70
|
```bash
|
|
59
|
-
npx dependency-radar --
|
|
71
|
+
npx dependency-radar --offline
|
|
60
72
|
```
|
|
61
73
|
|
|
62
74
|
Output JSON instead of HTML report:
|
|
@@ -65,6 +77,12 @@ Output JSON instead of HTML report:
|
|
|
65
77
|
npx dependency-radar --json
|
|
66
78
|
```
|
|
67
79
|
|
|
80
|
+
Open the generated report using the system default:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx dependency-radar --open
|
|
84
|
+
```
|
|
85
|
+
|
|
68
86
|
Show options:
|
|
69
87
|
|
|
70
88
|
```bash
|
|
@@ -81,7 +99,7 @@ npx dependency-radar --help
|
|
|
81
99
|
|
|
82
100
|
- The target project must have node_modules installed (run npm install first).
|
|
83
101
|
- The scan is local-first and does not upload your code or dependencies anywhere.
|
|
84
|
-
- `npm audit`
|
|
102
|
+
- `npm audit` and `npm outdated` perform registry lookups; use `--offline` for offline-only scans.
|
|
85
103
|
- A temporary `.dependency-radar` folder is created during the scan to store intermediate tool output.
|
|
86
104
|
- Use `--keep-temp` to retain this folder for debugging; otherwise it is deleted automatically.
|
|
87
105
|
- If a tool fails, its section is marked as unavailable, but the report is still generated.
|
|
@@ -99,27 +117,167 @@ The JSON schema matches the `AggregatedData` TypeScript interface in `src/types.
|
|
|
99
117
|
|
|
100
118
|
```ts
|
|
101
119
|
export interface AggregatedData {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
120
|
+
schemaVersion: '1.2'; // Report schema version for compatibility checks
|
|
121
|
+
generatedAt: string; // ISO timestamp when the scan finished
|
|
122
|
+
dependencyRadarVersion: string; // CLI version that produced the report
|
|
123
|
+
git: {
|
|
124
|
+
branch: string; // Git branch name, empty when unavailable/detached
|
|
125
|
+
};
|
|
126
|
+
project: {
|
|
127
|
+
projectDir: string; // Project path relative to the user's home directory (e.g. /Developer/app)
|
|
128
|
+
};
|
|
107
129
|
environment: {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
130
|
+
nodeVersion: string; // Node.js version from process.versions.node
|
|
131
|
+
runtimeVersion: string; // Node.js runtime version from process.version
|
|
132
|
+
minRequiredMajor: number; // Strictest Node major required by dependency engines (0 if unknown)
|
|
133
|
+
platform?: string; // OS platform (process.platform)
|
|
134
|
+
arch?: string; // CPU architecture (process.arch)
|
|
135
|
+
ci?: boolean; // True when running in CI (process.env.CI === 'true')
|
|
136
|
+
packageManagerField?: string; // package.json packageManager field (e.g. pnpm@9.1.0)
|
|
137
|
+
packageManager?: 'npm' | 'pnpm' | 'yarn'; // Package manager used to scan
|
|
138
|
+
packageManagerVersion?: string; // Version of the package manager used to scan
|
|
139
|
+
toolVersions?: {
|
|
140
|
+
npm?: string;
|
|
141
|
+
pnpm?: string;
|
|
142
|
+
yarn?: string;
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
workspaces: {
|
|
146
|
+
enabled: boolean; // True when the scan used workspace aggregation
|
|
147
|
+
type?: 'npm' | 'pnpm' | 'yarn' | 'none'; // Workspace type if detected
|
|
148
|
+
packageCount?: number; // Number of workspace packages scanned
|
|
149
|
+
};
|
|
150
|
+
summary: {
|
|
151
|
+
dependencyCount: number; // Total dependencies in the graph
|
|
152
|
+
directCount: number; // Dependencies listed in package.json
|
|
153
|
+
transitiveCount: number; // Dependencies pulled in by other dependencies
|
|
154
|
+
};
|
|
155
|
+
dependencies: Record<string, DependencyRecord>; // Keyed by name@version
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface DependencyRecord {
|
|
159
|
+
package: {
|
|
160
|
+
id: string; // Stable identifier in the form name@version
|
|
161
|
+
name: string; // Package name from npm metadata
|
|
162
|
+
version: string; // Installed version from npm ls
|
|
163
|
+
description?: string; // Description from the installed package.json (if present)
|
|
164
|
+
deprecated: boolean; // True if the package.json has a deprecated flag
|
|
165
|
+
links: {
|
|
166
|
+
npm: string; // npm package page URL
|
|
167
|
+
repository?: string; // Repository URL (if present)
|
|
168
|
+
homepage?: string; // Homepage URL (if present)
|
|
169
|
+
bugs?: string; // Issue tracker URL (if present)
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
compliance: {
|
|
173
|
+
license: {
|
|
174
|
+
declared?: {
|
|
175
|
+
spdxId: string; // SPDX ID or expression from package.json
|
|
176
|
+
expression: boolean; // True when SPDX expression (AND/OR/WITH)
|
|
177
|
+
deprecated: boolean; // True if SPDX ID is deprecated
|
|
178
|
+
valid: boolean; // True if SPDX ID/expression is valid
|
|
179
|
+
};
|
|
180
|
+
inferred?: {
|
|
181
|
+
spdxId: string; // SPDX ID inferred from LICENSE text
|
|
182
|
+
confidence: 'high' | 'medium' | 'low'; // Heuristic confidence
|
|
183
|
+
};
|
|
184
|
+
exception?: {
|
|
185
|
+
id: string; // SPDX exception id
|
|
186
|
+
deprecated: boolean; // True if exception is deprecated
|
|
187
|
+
valid: boolean; // True if exception id is valid
|
|
188
|
+
};
|
|
189
|
+
status:
|
|
190
|
+
| 'declared-only'
|
|
191
|
+
| 'inferred-only'
|
|
192
|
+
| 'match'
|
|
193
|
+
| 'mismatch'
|
|
194
|
+
| 'invalid-spdx'
|
|
195
|
+
| 'unknown';
|
|
196
|
+
};
|
|
197
|
+
licenseRisk: 'green' | 'amber' | 'red'; // Risk classification derived from declared/inferred SPDX ids
|
|
198
|
+
};
|
|
199
|
+
security: {
|
|
200
|
+
summary: {
|
|
201
|
+
critical: number; // npm audit counts for critical issues
|
|
202
|
+
high: number; // npm audit counts for high issues
|
|
203
|
+
moderate: number; // npm audit counts for moderate issues
|
|
204
|
+
low: number; // npm audit counts for low issues
|
|
205
|
+
highest: 'low' | 'moderate' | 'high' | 'critical' | 'none'; // Highest severity present
|
|
206
|
+
risk: 'green' | 'amber' | 'red'; // Risk classification derived from audit counts
|
|
207
|
+
};
|
|
208
|
+
advisories?: Array<{
|
|
209
|
+
id: string; // GHSA identifier
|
|
210
|
+
title: string; // Human-readable advisory title
|
|
211
|
+
severity: 'low' | 'moderate' | 'high' | 'critical';
|
|
212
|
+
vulnerableRange: string; // Semver range
|
|
213
|
+
fixAvailable: boolean; // True if npm audit indicates a fix exists
|
|
214
|
+
url: string; // Advisory URL
|
|
215
|
+
}>;
|
|
216
|
+
};
|
|
217
|
+
upgrade: {
|
|
218
|
+
nodeEngine: string | null; // engines.node from the package.json (if present)
|
|
219
|
+
outdatedStatus?: 'current' | 'patch' | 'minor' | 'major' | 'unknown'; // Derived from npm outdated (if present)
|
|
220
|
+
latestVersion?: string; // npm latest version (present only when status is not current)
|
|
221
|
+
blockers?: Array<'nodeEngine' | 'peerDependency' | 'nativeBindings' | 'deprecated'>; // Reasons for upgrade friction
|
|
222
|
+
blocksNodeMajor?: boolean; // True if local signals indicate a node major bump is risky
|
|
223
|
+
};
|
|
224
|
+
usage: {
|
|
225
|
+
direct: boolean; // True if declared in package.json (dependencies/devDependencies/etc.)
|
|
226
|
+
scope: 'runtime' | 'dev' | 'optional' | 'peer'; // Scope inferred from the declaring root package(s)
|
|
227
|
+
depth: number; // Minimum dependency tree depth observed in npm ls
|
|
228
|
+
origins: {
|
|
229
|
+
rootPackageCount: number; // Number of direct roots that introduce this dependency
|
|
230
|
+
topRootPackages: Array<{ name: string; version: string }>; // Up to 10 root packages (name/version)
|
|
231
|
+
parentPackageCount: number; // Number of direct parents
|
|
232
|
+
topParentPackages: string[]; // Up to 5 direct parent ids (name@version)
|
|
233
|
+
workspaces?: string[]; // Workspace packages that declare/use this dependency
|
|
234
|
+
};
|
|
235
|
+
introduction?: 'direct' | 'tooling' | 'framework' | 'testing' | 'transitive' | 'unknown'; // Heuristic for why the dependency exists
|
|
236
|
+
runtimeImpact?: 'runtime' | 'build' | 'testing' | 'tooling' | 'mixed'; // Heuristic based on import locations
|
|
237
|
+
importUsage?: {
|
|
238
|
+
fileCount: number; // Number of project files importing this package (import graph)
|
|
239
|
+
topFiles: string[]; // Top import locations (bounded to 5)
|
|
240
|
+
};
|
|
241
|
+
tsTypes: 'bundled' | 'definitelyTyped' | 'none' | 'unknown'; // TypeScript type availability
|
|
242
|
+
};
|
|
243
|
+
graph: {
|
|
244
|
+
fanIn: number; // Number of packages that depend on this package
|
|
245
|
+
fanOut: number; // Number of packages this package depends on
|
|
246
|
+
subDeps?: {
|
|
247
|
+
// Declared outgoing dependency edges; values are tuples.
|
|
248
|
+
// tuple[0] = declared version range, tuple[1] = resolved dependency id or null if not installed.
|
|
249
|
+
// Only installed dependencies have full dependency records in the top-level list.
|
|
250
|
+
dep?: Record<string, [string, string | null]>; // Declared runtime deps
|
|
251
|
+
dev?: Record<string, [string, string | null]>; // Declared dev deps
|
|
252
|
+
peer?: Record<string, [string, string | null]>; // Declared peer deps
|
|
253
|
+
opt?: Record<string, [string, string | null]>; // Declared optional deps
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
execution?: {
|
|
257
|
+
risk: 'amber' | 'red'; // Install-time risk (green implied when absent)
|
|
258
|
+
native?: true; // True if native bindings or build tooling are detected
|
|
259
|
+
scripts?: {
|
|
260
|
+
hooks: Array<'preinstall' | 'install' | 'postinstall' | 'prepare'>; // Lifecycle hooks detected
|
|
261
|
+
complexity?: number; // Heuristic complexity (stored only when high)
|
|
262
|
+
signals?: Array<
|
|
263
|
+
| 'network-access'
|
|
264
|
+
| 'dynamic-exec'
|
|
265
|
+
| 'child-process'
|
|
266
|
+
| 'encoding'
|
|
267
|
+
| 'obfuscated'
|
|
268
|
+
| 'reads-env'
|
|
269
|
+
| 'reads-home'
|
|
270
|
+
| 'uses-ssh'
|
|
271
|
+
>; // Review-worthy install-time signals (sparse)
|
|
113
272
|
};
|
|
114
273
|
};
|
|
115
|
-
dependencies: DependencyRecord[];
|
|
116
|
-
toolErrors: Record<string, string>;
|
|
117
|
-
raw: RawOutputs;
|
|
118
|
-
importAnalysis?: ImportAnalysisSummary;
|
|
119
274
|
}
|
|
120
275
|
```
|
|
121
276
|
|
|
122
|
-
For full details
|
|
277
|
+
For full details and any future changes, see `src/types.ts`.
|
|
278
|
+
|
|
279
|
+
Environment data includes Node.js version, OS platform, CPU architecture, and package manager versions.
|
|
280
|
+
No personal information, usernames, paths, or environment variables are collected.
|
|
123
281
|
|
|
124
282
|
## Development
|
|
125
283
|
|
|
@@ -149,4 +307,3 @@ This opens the report UI in your browser with sample data covering all dependenc
|
|
|
149
307
|
- `report-ui/sample-data.json` – Sample data for development
|
|
150
308
|
- `report-ui/types.ts` – Client-side TypeScript types
|
|
151
309
|
- `src/report-assets.ts` – Auto-generated file with bundled CSS/JS (do not edit directly)
|
|
152
|
-
|