dep-brain 0.1.3 → 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 CHANGED
@@ -107,6 +107,12 @@ Create a `depbrain.config.json` file in the project root:
107
107
  },
108
108
  "report": {
109
109
  "maxSuggestions": 3
110
+ },
111
+ "scoring": {
112
+ "duplicateWeight": 5,
113
+ "outdatedWeight": 1,
114
+ "unusedWeight": 2,
115
+ "riskWeight": 6
110
116
  }
111
117
  }
112
118
  ```
@@ -125,6 +131,10 @@ Supported sections:
125
131
  - `policy.failOnOutdated`
126
132
  - `policy.failOnRisks`
127
133
  - `report.maxSuggestions`
134
+ - `scoring.duplicateWeight`
135
+ - `scoring.outdatedWeight`
136
+ - `scoring.unusedWeight`
137
+ - `scoring.riskWeight`
128
138
 
129
139
  Sample config file:
130
140
 
@@ -16,5 +16,11 @@
16
16
  },
17
17
  "report": {
18
18
  "maxSuggestions": 5
19
+ },
20
+ "scoring": {
21
+ "duplicateWeight": 5,
22
+ "outdatedWeight": 3,
23
+ "unusedWeight": 4,
24
+ "riskWeight": 10
19
25
  }
20
26
  }
@@ -33,6 +33,16 @@
33
33
  "properties": {
34
34
  "maxSuggestions": { "type": "number" }
35
35
  }
36
+ },
37
+ "scoring": {
38
+ "type": "object",
39
+ "additionalProperties": false,
40
+ "properties": {
41
+ "duplicateWeight": { "type": "number" },
42
+ "outdatedWeight": { "type": "number" },
43
+ "unusedWeight": { "type": "number" },
44
+ "riskWeight": { "type": "number" }
45
+ }
36
46
  }
37
47
  }
38
48
  }
package/dist/cli.js CHANGED
@@ -77,22 +77,34 @@ async function main() {
77
77
  configPath: optionValues.get("--config"),
78
78
  config: cliConfig
79
79
  });
80
- const output = flags.has("--json")
81
- ? renderJsonReport(result)
82
- : renderConsoleReport(result);
83
- if (!output || output.trim().length === 0) {
84
- console.log(renderJsonReport(result));
80
+ if (flags.has("--json")) {
81
+ process.stdout.write(`${renderJsonReport(result)}\n`);
85
82
  }
86
83
  else {
87
- console.log(output);
84
+ const output = renderConsoleReport(result);
85
+ if (!output || output.trim().length === 0) {
86
+ process.stdout.write(`${renderJsonReport(result)}\n`);
87
+ }
88
+ else {
89
+ process.stdout.write(`${output}\n`);
90
+ }
88
91
  }
89
92
  if (!result.policy.passed) {
90
93
  process.exitCode = 1;
91
94
  }
92
95
  }
93
96
  catch (error) {
94
- console.error("Analysis failed.");
95
- console.error(error);
97
+ if (flags.has("--json")) {
98
+ const payload = {
99
+ error: "Analysis failed",
100
+ message: error instanceof Error ? error.message : String(error)
101
+ };
102
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
103
+ }
104
+ else {
105
+ console.error("Analysis failed.");
106
+ console.error(error);
107
+ }
96
108
  process.exitCode = 1;
97
109
  }
98
110
  }
@@ -33,6 +33,7 @@ export interface RiskDependency {
33
33
  export interface AnalysisResult {
34
34
  rootDir: string;
35
35
  score: number;
36
+ scoreBreakdown: ScoreBreakdown;
36
37
  policy: PolicyResult;
37
38
  duplicates: DuplicateDependency[];
38
39
  unused: UnusedDependency[];
@@ -50,6 +51,7 @@ export interface PackageAnalysisResult {
50
51
  name: string;
51
52
  rootDir: string;
52
53
  score: number;
54
+ scoreBreakdown: ScoreBreakdown;
53
55
  policy: PolicyResult;
54
56
  duplicates: DuplicateDependency[];
55
57
  unused: UnusedDependency[];
@@ -57,4 +59,17 @@ export interface PackageAnalysisResult {
57
59
  risks: RiskDependency[];
58
60
  suggestions: string[];
59
61
  }
62
+ export interface ScoreBreakdown {
63
+ baseScore: number;
64
+ duplicates: number;
65
+ outdated: number;
66
+ unused: number;
67
+ risks: number;
68
+ weights: {
69
+ duplicateWeight: number;
70
+ outdatedWeight: number;
71
+ unusedWeight: number;
72
+ riskWeight: number;
73
+ };
74
+ }
60
75
  export declare function analyzeProject(options?: AnalysisOptions): Promise<AnalysisResult>;
@@ -32,8 +32,18 @@ export async function analyzeProject(options = {}) {
32
32
  duplicates: duplicates.length,
33
33
  unused: unused.length,
34
34
  outdated: outdated.length,
35
- risks: risks.length
35
+ risks: risks.length,
36
+ duplicateWeight: config.scoring.duplicateWeight,
37
+ outdatedWeight: config.scoring.outdatedWeight,
38
+ unusedWeight: config.scoring.unusedWeight,
39
+ riskWeight: config.scoring.riskWeight
36
40
  });
41
+ const scoreBreakdown = buildScoreBreakdown({
42
+ duplicates: duplicates.length,
43
+ unused: unused.length,
44
+ outdated: outdated.length,
45
+ risks: risks.length
46
+ }, config);
37
47
  const suggestions = [
38
48
  ...packages.flatMap((pkg) => pkg.suggestions.map((suggestion) => `[${pkg.name}] ${suggestion}`))
39
49
  ].slice(0, config.report.maxSuggestions);
@@ -47,6 +57,7 @@ export async function analyzeProject(options = {}) {
47
57
  return {
48
58
  rootDir,
49
59
  score,
60
+ scoreBreakdown,
50
61
  policy,
51
62
  duplicates,
52
63
  unused,
@@ -79,6 +90,12 @@ function mergeConfig(base, overrides) {
79
90
  },
80
91
  report: {
81
92
  maxSuggestions: overrides.report?.maxSuggestions ?? base.report.maxSuggestions
93
+ },
94
+ scoring: {
95
+ duplicateWeight: overrides.scoring?.duplicateWeight ?? base.scoring.duplicateWeight,
96
+ outdatedWeight: overrides.scoring?.outdatedWeight ?? base.scoring.outdatedWeight,
97
+ unusedWeight: overrides.scoring?.unusedWeight ?? base.scoring.unusedWeight,
98
+ riskWeight: overrides.scoring?.riskWeight ?? base.scoring.riskWeight
82
99
  }
83
100
  };
84
101
  }
@@ -121,8 +138,18 @@ async function analyzeSingleProject(rootDir, config, options = {}) {
121
138
  duplicates: duplicates.length,
122
139
  unused: unused.length,
123
140
  outdated: outdated.length,
124
- risks: risks.length
141
+ risks: risks.length,
142
+ duplicateWeight: config.scoring.duplicateWeight,
143
+ outdatedWeight: config.scoring.outdatedWeight,
144
+ unusedWeight: config.scoring.unusedWeight,
145
+ riskWeight: config.scoring.riskWeight
125
146
  });
147
+ const scoreBreakdown = buildScoreBreakdown({
148
+ duplicates: duplicates.length,
149
+ unused: unused.length,
150
+ outdated: outdated.length,
151
+ risks: risks.length
152
+ }, config);
126
153
  const suggestions = [
127
154
  ...unused.map((item) => `Remove ${item.name} from ${item.section}`),
128
155
  ...duplicates.map((item) => `Consider consolidating ${item.name} to one version`),
@@ -147,6 +174,7 @@ async function analyzeSingleProject(rootDir, config, options = {}) {
147
174
  return {
148
175
  rootDir,
149
176
  score,
177
+ scoreBreakdown,
150
178
  policy,
151
179
  duplicates,
152
180
  unused: scopedUnused,
@@ -156,3 +184,18 @@ async function analyzeSingleProject(rootDir, config, options = {}) {
156
184
  config
157
185
  };
158
186
  }
187
+ function buildScoreBreakdown(counts, config) {
188
+ return {
189
+ baseScore: 100,
190
+ duplicates: counts.duplicates * config.scoring.duplicateWeight,
191
+ outdated: counts.outdated * config.scoring.outdatedWeight,
192
+ unused: counts.unused * config.scoring.unusedWeight,
193
+ risks: counts.risks * config.scoring.riskWeight,
194
+ weights: {
195
+ duplicateWeight: config.scoring.duplicateWeight,
196
+ outdatedWeight: config.scoring.outdatedWeight,
197
+ unusedWeight: config.scoring.unusedWeight,
198
+ riskWeight: config.scoring.riskWeight
199
+ }
200
+ };
201
+ }
@@ -3,5 +3,9 @@ export interface ScoreInputs {
3
3
  unused: number;
4
4
  outdated: number;
5
5
  risks: number;
6
+ duplicateWeight?: number;
7
+ unusedWeight?: number;
8
+ outdatedWeight?: number;
9
+ riskWeight?: number;
6
10
  }
7
11
  export declare function calculateHealthScore(inputs: ScoreInputs): number;
@@ -1,8 +1,12 @@
1
1
  export function calculateHealthScore(inputs) {
2
+ const duplicateWeight = inputs.duplicateWeight ?? 5;
3
+ const outdatedWeight = inputs.outdatedWeight ?? 3;
4
+ const unusedWeight = inputs.unusedWeight ?? 4;
5
+ const riskWeight = inputs.riskWeight ?? 10;
2
6
  const rawScore = 100 -
3
- inputs.duplicates * 5 -
4
- inputs.outdated * 3 -
5
- inputs.unused * 4 -
6
- inputs.risks * 10;
7
+ inputs.duplicates * duplicateWeight -
8
+ inputs.outdated * outdatedWeight -
9
+ inputs.unused * unusedWeight -
10
+ inputs.risks * riskWeight;
7
11
  return Math.max(0, rawScore);
8
12
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { analyzeProject } from "./core/analyzer.js";
2
- export type { AnalysisOptions, AnalysisResult, DuplicateDependency, OutdatedDependency, PolicyResult, PackageAnalysisResult, RiskDependency, UnusedDependency } from "./core/analyzer.js";
2
+ export type { AnalysisOptions, AnalysisResult, DuplicateDependency, OutdatedDependency, PolicyResult, PackageAnalysisResult, ScoreBreakdown, RiskDependency, UnusedDependency } from "./core/analyzer.js";
3
3
  export type { DepBrainConfig, DepBrainConfigOverrides } from "./utils/config.js";
4
4
  export type { WorkspacePackage } from "./utils/workspaces.js";
@@ -3,6 +3,7 @@ export function renderConsoleReport(result) {
3
3
  lines.push(`Project Health: ${result.score}/100`);
4
4
  lines.push(`Path: ${result.rootDir}`);
5
5
  lines.push(`Policy: ${result.policy.passed ? "PASS" : "FAIL"}`);
6
+ lines.push(`Score Breakdown: base ${result.scoreBreakdown.baseScore} - dup ${result.scoreBreakdown.duplicates} - outdated ${result.scoreBreakdown.outdated} - unused ${result.scoreBreakdown.unused} - risk ${result.scoreBreakdown.risks}`);
6
7
  lines.push("");
7
8
  lines.push(summaryLine("Duplicates", result.duplicates.length));
8
9
  lines.push(summaryLine("Unused", result.unused.length));
@@ -17,11 +17,18 @@ export interface DepBrainConfig {
17
17
  report: {
18
18
  maxSuggestions: number;
19
19
  };
20
+ scoring: {
21
+ duplicateWeight: number;
22
+ outdatedWeight: number;
23
+ unusedWeight: number;
24
+ riskWeight: number;
25
+ };
20
26
  }
21
27
  export interface DepBrainConfigOverrides {
22
28
  ignore?: Partial<DepBrainConfig["ignore"]>;
23
29
  policy?: Partial<DepBrainConfig["policy"]>;
24
30
  report?: Partial<DepBrainConfig["report"]>;
31
+ scoring?: Partial<DepBrainConfig["scoring"]>;
25
32
  }
26
33
  export declare const defaultConfig: DepBrainConfig;
27
34
  export declare function loadDepBrainConfig(rootDir: string, configPath?: string): Promise<DepBrainConfig>;
@@ -18,6 +18,12 @@ export const defaultConfig = {
18
18
  },
19
19
  report: {
20
20
  maxSuggestions: 5
21
+ },
22
+ scoring: {
23
+ duplicateWeight: 5,
24
+ outdatedWeight: 3,
25
+ unusedWeight: 4,
26
+ riskWeight: 10
21
27
  }
22
28
  };
23
29
  export async function loadDepBrainConfig(rootDir, configPath) {
@@ -49,6 +55,12 @@ function normalizeConfig(loaded) {
49
55
  },
50
56
  report: {
51
57
  maxSuggestions: normalizeNumber(loaded.report?.maxSuggestions, defaultConfig.report.maxSuggestions)
58
+ },
59
+ scoring: {
60
+ duplicateWeight: normalizeNumber(loaded.scoring?.duplicateWeight, defaultConfig.scoring.duplicateWeight),
61
+ outdatedWeight: normalizeNumber(loaded.scoring?.outdatedWeight, defaultConfig.scoring.outdatedWeight),
62
+ unusedWeight: normalizeNumber(loaded.scoring?.unusedWeight, defaultConfig.scoring.unusedWeight),
63
+ riskWeight: normalizeNumber(loaded.scoring?.riskWeight, defaultConfig.scoring.riskWeight)
52
64
  }
53
65
  };
54
66
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dep-brain",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "CLI and library for dependency health analysis",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",