dep-brain 0.2.1 → 0.4.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 +15 -1
- package/depbrain.config.json +6 -1
- package/depbrain.config.schema.json +10 -1
- package/depbrain.output.schema.json +112 -0
- package/dist/checks/unused.d.ts +3 -1
- package/dist/checks/unused.js +2 -2
- package/dist/core/analyzer.d.ts +2 -0
- package/dist/core/analyzer.js +35 -8
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/utils/config.d.ts +6 -0
- package/dist/utils/config.js +12 -2
- package/dist/utils/file-parser.d.ts +1 -1
- package/dist/utils/file-parser.js +34 -4
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -46,6 +46,7 @@ npx dep-brain analyze ./path-to-project
|
|
|
46
46
|
npx dep-brain analyze --config depbrain.config.json
|
|
47
47
|
npx dep-brain analyze --min-score 90 --fail-on-risks
|
|
48
48
|
npx dep-brain analyze ./path-to-project --fail-on-unused --json
|
|
49
|
+
npx dep-brain analyze --md > depbrain.md
|
|
49
50
|
|
|
50
51
|
dep-brain config
|
|
51
52
|
dep-brain config --config depbrain.config.json
|
|
@@ -91,6 +92,10 @@ Suggestions:
|
|
|
91
92
|
dep-brain analyze --json
|
|
92
93
|
```
|
|
93
94
|
|
|
95
|
+
Output includes `outputVersion` for schema stability and can be validated with:
|
|
96
|
+
|
|
97
|
+
- `depbrain.output.schema.json`
|
|
98
|
+
|
|
94
99
|
## Markdown Output
|
|
95
100
|
|
|
96
101
|
```bash
|
|
@@ -105,7 +110,9 @@ Create a `depbrain.config.json` file in the project root:
|
|
|
105
110
|
{
|
|
106
111
|
"ignore": {
|
|
107
112
|
"unused": ["eslint"],
|
|
108
|
-
"outdated": ["typescript"]
|
|
113
|
+
"outdated": ["typescript"],
|
|
114
|
+
"prefixes": ["@nestjs/"],
|
|
115
|
+
"patterns": ["^@aws-sdk/"]
|
|
109
116
|
},
|
|
110
117
|
"policy": {
|
|
111
118
|
"minScore": 90,
|
|
@@ -120,6 +127,9 @@ Create a `depbrain.config.json` file in the project root:
|
|
|
120
127
|
"outdatedWeight": 1,
|
|
121
128
|
"unusedWeight": 2,
|
|
122
129
|
"riskWeight": 6
|
|
130
|
+
},
|
|
131
|
+
"scan": {
|
|
132
|
+
"excludePaths": ["node_modules", "dist", "build", "coverage", ".git"]
|
|
123
133
|
}
|
|
124
134
|
}
|
|
125
135
|
```
|
|
@@ -142,11 +152,15 @@ Supported sections:
|
|
|
142
152
|
- `scoring.outdatedWeight`
|
|
143
153
|
- `scoring.unusedWeight`
|
|
144
154
|
- `scoring.riskWeight`
|
|
155
|
+
- `ignore.prefixes`
|
|
156
|
+
- `ignore.patterns`
|
|
157
|
+
- `scan.excludePaths`
|
|
145
158
|
|
|
146
159
|
Sample config file:
|
|
147
160
|
|
|
148
161
|
- `depbrain.config.json`
|
|
149
162
|
- `depbrain.config.schema.json`
|
|
163
|
+
- `depbrain.output.schema.json`
|
|
150
164
|
|
|
151
165
|
## CI Behavior
|
|
152
166
|
|
package/depbrain.config.json
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
"duplicates": [],
|
|
6
6
|
"risks": [],
|
|
7
7
|
"dependencies": [],
|
|
8
|
-
"devDependencies": []
|
|
8
|
+
"devDependencies": [],
|
|
9
|
+
"prefixes": [],
|
|
10
|
+
"patterns": []
|
|
9
11
|
},
|
|
10
12
|
"policy": {
|
|
11
13
|
"minScore": 85,
|
|
@@ -22,5 +24,8 @@
|
|
|
22
24
|
"outdatedWeight": 3,
|
|
23
25
|
"unusedWeight": 4,
|
|
24
26
|
"riskWeight": 10
|
|
27
|
+
},
|
|
28
|
+
"scan": {
|
|
29
|
+
"excludePaths": ["node_modules", "dist", "build", "coverage", ".git"]
|
|
25
30
|
}
|
|
26
31
|
}
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
"unused": { "type": "array", "items": { "type": "string" } },
|
|
14
14
|
"duplicates": { "type": "array", "items": { "type": "string" } },
|
|
15
15
|
"outdated": { "type": "array", "items": { "type": "string" } },
|
|
16
|
-
"risks": { "type": "array", "items": { "type": "string" } }
|
|
16
|
+
"risks": { "type": "array", "items": { "type": "string" } },
|
|
17
|
+
"prefixes": { "type": "array", "items": { "type": "string" } },
|
|
18
|
+
"patterns": { "type": "array", "items": { "type": "string" } }
|
|
17
19
|
}
|
|
18
20
|
},
|
|
19
21
|
"policy": {
|
|
@@ -43,6 +45,13 @@
|
|
|
43
45
|
"unusedWeight": { "type": "number" },
|
|
44
46
|
"riskWeight": { "type": "number" }
|
|
45
47
|
}
|
|
48
|
+
},
|
|
49
|
+
"scan": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"additionalProperties": false,
|
|
52
|
+
"properties": {
|
|
53
|
+
"excludePaths": { "type": "array", "items": { "type": "string" } }
|
|
54
|
+
}
|
|
46
55
|
}
|
|
47
56
|
}
|
|
48
57
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "Dependency Brain Analysis Output",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["outputVersion", "rootDir", "score", "scoreBreakdown", "policy", "duplicates", "unused", "outdated", "risks", "suggestions", "config"],
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"properties": {
|
|
8
|
+
"outputVersion": { "type": "string" },
|
|
9
|
+
"rootDir": { "type": "string" },
|
|
10
|
+
"score": { "type": "number" },
|
|
11
|
+
"scoreBreakdown": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"required": ["baseScore", "duplicates", "outdated", "unused", "risks", "weights"],
|
|
14
|
+
"additionalProperties": false,
|
|
15
|
+
"properties": {
|
|
16
|
+
"baseScore": { "type": "number" },
|
|
17
|
+
"duplicates": { "type": "number" },
|
|
18
|
+
"outdated": { "type": "number" },
|
|
19
|
+
"unused": { "type": "number" },
|
|
20
|
+
"risks": { "type": "number" },
|
|
21
|
+
"weights": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"required": ["duplicateWeight", "outdatedWeight", "unusedWeight", "riskWeight"],
|
|
24
|
+
"additionalProperties": false,
|
|
25
|
+
"properties": {
|
|
26
|
+
"duplicateWeight": { "type": "number" },
|
|
27
|
+
"outdatedWeight": { "type": "number" },
|
|
28
|
+
"unusedWeight": { "type": "number" },
|
|
29
|
+
"riskWeight": { "type": "number" }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"policy": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"required": ["passed", "reasons"],
|
|
37
|
+
"additionalProperties": false,
|
|
38
|
+
"properties": {
|
|
39
|
+
"passed": { "type": "boolean" },
|
|
40
|
+
"reasons": { "type": "array", "items": { "type": "string" } }
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"duplicates": {
|
|
44
|
+
"type": "array",
|
|
45
|
+
"items": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"required": ["name", "versions", "instances"],
|
|
48
|
+
"additionalProperties": false,
|
|
49
|
+
"properties": {
|
|
50
|
+
"name": { "type": "string" },
|
|
51
|
+
"versions": { "type": "array", "items": { "type": "string" } },
|
|
52
|
+
"instances": {
|
|
53
|
+
"type": "array",
|
|
54
|
+
"items": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"required": ["path", "version"],
|
|
57
|
+
"additionalProperties": false,
|
|
58
|
+
"properties": {
|
|
59
|
+
"path": { "type": "string" },
|
|
60
|
+
"version": { "type": "string" }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"unused": {
|
|
68
|
+
"type": "array",
|
|
69
|
+
"items": {
|
|
70
|
+
"type": "object",
|
|
71
|
+
"required": ["name", "section"],
|
|
72
|
+
"additionalProperties": false,
|
|
73
|
+
"properties": {
|
|
74
|
+
"name": { "type": "string" },
|
|
75
|
+
"section": { "type": "string", "enum": ["dependencies", "devDependencies"] },
|
|
76
|
+
"package": { "type": "string" }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"outdated": {
|
|
81
|
+
"type": "array",
|
|
82
|
+
"items": {
|
|
83
|
+
"type": "object",
|
|
84
|
+
"required": ["name", "current", "latest", "updateType"],
|
|
85
|
+
"additionalProperties": false,
|
|
86
|
+
"properties": {
|
|
87
|
+
"name": { "type": "string" },
|
|
88
|
+
"current": { "type": "string" },
|
|
89
|
+
"latest": { "type": "string" },
|
|
90
|
+
"updateType": { "type": "string" },
|
|
91
|
+
"package": { "type": "string" }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"risks": {
|
|
96
|
+
"type": "array",
|
|
97
|
+
"items": {
|
|
98
|
+
"type": "object",
|
|
99
|
+
"required": ["name", "reasons"],
|
|
100
|
+
"additionalProperties": false,
|
|
101
|
+
"properties": {
|
|
102
|
+
"name": { "type": "string" },
|
|
103
|
+
"reasons": { "type": "array", "items": { "type": "string" } },
|
|
104
|
+
"package": { "type": "string" }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"suggestions": { "type": "array", "items": { "type": "string" } },
|
|
109
|
+
"config": { "type": "object" },
|
|
110
|
+
"packages": { "type": "array" }
|
|
111
|
+
}
|
|
112
|
+
}
|
package/dist/checks/unused.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { UnusedDependency } from "../core/analyzer.js";
|
|
2
2
|
import type { DependencyGraph } from "../core/graph-builder.js";
|
|
3
|
-
export declare function findUnusedDependencies(rootDir: string, graph: DependencyGraph
|
|
3
|
+
export declare function findUnusedDependencies(rootDir: string, graph: DependencyGraph, options?: {
|
|
4
|
+
excludePaths?: string[];
|
|
5
|
+
}): Promise<UnusedDependency[]>;
|
package/dist/checks/unused.js
CHANGED
|
@@ -4,8 +4,8 @@ const SOURCE_FILE_PATTERN = /\.(c|m)?(t|j)sx?$/;
|
|
|
4
4
|
const CONFIG_FILE_PATTERN = /(^|[\\/])(vite|vitest|jest|eslint|prettier|rollup|webpack|babel|tsup|eslint\.config|commitlint|playwright|storybook|tailwind|postcss)\.config\.(c|m)?(t|j)s$/;
|
|
5
5
|
const TEST_FILE_PATTERN = /(^|[\\/])(__tests__|test|tests|spec|specs)([\\/]|$)|\.(test|spec)\.(c|m)?(t|j)sx?$/;
|
|
6
6
|
const RUNTIME_DIR_PATTERN = /(^|[\\/])(src|app|lib|server|client|pages|components)([\\/]|$)/;
|
|
7
|
-
export async function findUnusedDependencies(rootDir, graph) {
|
|
8
|
-
const files = await collectProjectFiles(rootDir, SOURCE_FILE_PATTERN);
|
|
7
|
+
export async function findUnusedDependencies(rootDir, graph, options = {}) {
|
|
8
|
+
const files = await collectProjectFiles(rootDir, SOURCE_FILE_PATTERN, options.excludePaths ?? []);
|
|
9
9
|
const projectFiles = files.filter((filePath) => !filePath.includes(`${path.sep}node_modules${path.sep}`));
|
|
10
10
|
const runtimeUsed = new Set();
|
|
11
11
|
const devUsed = new Set();
|
package/dist/core/analyzer.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export interface RiskDependency {
|
|
|
31
31
|
package?: string;
|
|
32
32
|
}
|
|
33
33
|
export interface AnalysisResult {
|
|
34
|
+
outputVersion: string;
|
|
34
35
|
rootDir: string;
|
|
35
36
|
score: number;
|
|
36
37
|
scoreBreakdown: ScoreBreakdown;
|
|
@@ -59,6 +60,7 @@ export interface PackageAnalysisResult {
|
|
|
59
60
|
risks: RiskDependency[];
|
|
60
61
|
suggestions: string[];
|
|
61
62
|
}
|
|
63
|
+
export declare const OUTPUT_VERSION = "1.0";
|
|
62
64
|
export interface ScoreBreakdown {
|
|
63
65
|
baseScore: number;
|
|
64
66
|
duplicates: number;
|
package/dist/core/analyzer.js
CHANGED
|
@@ -7,6 +7,7 @@ import { loadDepBrainConfig } from "../utils/config.js";
|
|
|
7
7
|
import { findWorkspacePackages } from "../utils/workspaces.js";
|
|
8
8
|
import { buildDependencyGraph } from "./graph-builder.js";
|
|
9
9
|
import { calculateHealthScore } from "./scorer.js";
|
|
10
|
+
export const OUTPUT_VERSION = "1.0";
|
|
10
11
|
export async function analyzeProject(options = {}) {
|
|
11
12
|
const rootDir = path.resolve(options.rootDir ?? process.cwd());
|
|
12
13
|
const loadedConfig = await loadDepBrainConfig(rootDir, options.configPath);
|
|
@@ -17,7 +18,7 @@ export async function analyzeProject(options = {}) {
|
|
|
17
18
|
}
|
|
18
19
|
const rootGraph = await buildDependencyGraph(rootDir);
|
|
19
20
|
const rawDuplicates = await findDuplicateDependencies(rootGraph);
|
|
20
|
-
const duplicates = rawDuplicates.filter((item) => !
|
|
21
|
+
const duplicates = rawDuplicates.filter((item) => !shouldIgnorePackage(item.name, "duplicates", config));
|
|
21
22
|
const packages = [];
|
|
22
23
|
for (const workspace of workspaces) {
|
|
23
24
|
const result = await analyzeSingleProject(workspace.rootDir, config, {
|
|
@@ -55,6 +56,7 @@ export async function analyzeProject(options = {}) {
|
|
|
55
56
|
risks: risks.length
|
|
56
57
|
}, config);
|
|
57
58
|
return {
|
|
59
|
+
outputVersion: OUTPUT_VERSION,
|
|
58
60
|
rootDir,
|
|
59
61
|
score,
|
|
60
62
|
scoreBreakdown,
|
|
@@ -79,7 +81,9 @@ function mergeConfig(base, overrides) {
|
|
|
79
81
|
duplicates: overrides.ignore?.duplicates ?? base.ignore.duplicates,
|
|
80
82
|
outdated: overrides.ignore?.outdated ?? base.ignore.outdated,
|
|
81
83
|
risks: overrides.ignore?.risks ?? base.ignore.risks,
|
|
82
|
-
unused: overrides.ignore?.unused ?? base.ignore.unused
|
|
84
|
+
unused: overrides.ignore?.unused ?? base.ignore.unused,
|
|
85
|
+
prefixes: overrides.ignore?.prefixes ?? base.ignore.prefixes,
|
|
86
|
+
patterns: overrides.ignore?.patterns ?? base.ignore.patterns
|
|
83
87
|
},
|
|
84
88
|
policy: {
|
|
85
89
|
minScore: overrides.policy?.minScore ?? base.policy.minScore,
|
|
@@ -96,6 +100,9 @@ function mergeConfig(base, overrides) {
|
|
|
96
100
|
outdatedWeight: overrides.scoring?.outdatedWeight ?? base.scoring.outdatedWeight,
|
|
97
101
|
unusedWeight: overrides.scoring?.unusedWeight ?? base.scoring.unusedWeight,
|
|
98
102
|
riskWeight: overrides.scoring?.riskWeight ?? base.scoring.riskWeight
|
|
103
|
+
},
|
|
104
|
+
scan: {
|
|
105
|
+
excludePaths: overrides.scan?.excludePaths ?? base.scan.excludePaths
|
|
99
106
|
}
|
|
100
107
|
};
|
|
101
108
|
}
|
|
@@ -125,15 +132,17 @@ async function analyzeSingleProject(rootDir, config, options = {}) {
|
|
|
125
132
|
const graph = await buildDependencyGraph(rootDir);
|
|
126
133
|
const [rawDuplicates, rawUnused, rawOutdated, rawRisks] = await Promise.all([
|
|
127
134
|
findDuplicateDependencies(graph),
|
|
128
|
-
findUnusedDependencies(rootDir, graph
|
|
135
|
+
findUnusedDependencies(rootDir, graph, {
|
|
136
|
+
excludePaths: config.scan.excludePaths
|
|
137
|
+
}),
|
|
129
138
|
findOutdatedDependencies(graph),
|
|
130
139
|
findRiskDependencies(graph)
|
|
131
140
|
]);
|
|
132
|
-
const duplicates = rawDuplicates.filter((item) => !
|
|
133
|
-
const unused = rawUnused.filter((item) => !
|
|
134
|
-
!
|
|
135
|
-
const outdated = rawOutdated.filter((item) => !
|
|
136
|
-
const risks = rawRisks.filter((item) => !
|
|
141
|
+
const duplicates = rawDuplicates.filter((item) => !shouldIgnorePackage(item.name, "duplicates", config));
|
|
142
|
+
const unused = rawUnused.filter((item) => !shouldIgnorePackage(item.name, "unused", config) &&
|
|
143
|
+
!shouldIgnorePackage(item.name, item.section, config));
|
|
144
|
+
const outdated = rawOutdated.filter((item) => !shouldIgnorePackage(item.name, "outdated", config));
|
|
145
|
+
const risks = rawRisks.filter((item) => !shouldIgnorePackage(item.name, "risks", config));
|
|
137
146
|
const score = calculateHealthScore({
|
|
138
147
|
duplicates: duplicates.length,
|
|
139
148
|
unused: unused.length,
|
|
@@ -172,6 +181,7 @@ async function analyzeSingleProject(rootDir, config, options = {}) {
|
|
|
172
181
|
? risks.map((item) => ({ ...item, package: options.packageName }))
|
|
173
182
|
: risks;
|
|
174
183
|
return {
|
|
184
|
+
outputVersion: OUTPUT_VERSION,
|
|
175
185
|
rootDir,
|
|
176
186
|
score,
|
|
177
187
|
scoreBreakdown,
|
|
@@ -184,6 +194,23 @@ async function analyzeSingleProject(rootDir, config, options = {}) {
|
|
|
184
194
|
config
|
|
185
195
|
};
|
|
186
196
|
}
|
|
197
|
+
function shouldIgnorePackage(name, bucket, config) {
|
|
198
|
+
if (config.ignore[bucket].includes(name)) {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
if (config.ignore.prefixes.some((prefix) => name.startsWith(prefix))) {
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
return config.ignore.patterns.some((pattern) => {
|
|
205
|
+
try {
|
|
206
|
+
const regex = new RegExp(pattern);
|
|
207
|
+
return regex.test(name);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
187
214
|
function buildScoreBreakdown(counts, config) {
|
|
188
215
|
return {
|
|
189
216
|
baseScore: 100,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { analyzeProject } from "./core/analyzer.js";
|
|
2
2
|
export type { AnalysisOptions, AnalysisResult, DuplicateDependency, OutdatedDependency, PolicyResult, PackageAnalysisResult, ScoreBreakdown, RiskDependency, UnusedDependency } from "./core/analyzer.js";
|
|
3
|
+
export { OUTPUT_VERSION } from "./core/analyzer.js";
|
|
3
4
|
export type { DepBrainConfig, DepBrainConfigOverrides } from "./utils/config.js";
|
|
4
5
|
export type { WorkspacePackage } from "./utils/workspaces.js";
|
package/dist/index.js
CHANGED
package/dist/utils/config.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export interface DepBrainConfig {
|
|
|
6
6
|
outdated: string[];
|
|
7
7
|
risks: string[];
|
|
8
8
|
unused: string[];
|
|
9
|
+
prefixes: string[];
|
|
10
|
+
patterns: string[];
|
|
9
11
|
};
|
|
10
12
|
policy: {
|
|
11
13
|
minScore: number;
|
|
@@ -23,12 +25,16 @@ export interface DepBrainConfig {
|
|
|
23
25
|
unusedWeight: number;
|
|
24
26
|
riskWeight: number;
|
|
25
27
|
};
|
|
28
|
+
scan: {
|
|
29
|
+
excludePaths: string[];
|
|
30
|
+
};
|
|
26
31
|
}
|
|
27
32
|
export interface DepBrainConfigOverrides {
|
|
28
33
|
ignore?: Partial<DepBrainConfig["ignore"]>;
|
|
29
34
|
policy?: Partial<DepBrainConfig["policy"]>;
|
|
30
35
|
report?: Partial<DepBrainConfig["report"]>;
|
|
31
36
|
scoring?: Partial<DepBrainConfig["scoring"]>;
|
|
37
|
+
scan?: Partial<DepBrainConfig["scan"]>;
|
|
32
38
|
}
|
|
33
39
|
export declare const defaultConfig: DepBrainConfig;
|
|
34
40
|
export declare function loadDepBrainConfig(rootDir: string, configPath?: string): Promise<DepBrainConfig>;
|
package/dist/utils/config.js
CHANGED
|
@@ -7,7 +7,9 @@ export const defaultConfig = {
|
|
|
7
7
|
duplicates: [],
|
|
8
8
|
outdated: [],
|
|
9
9
|
risks: [],
|
|
10
|
-
unused: []
|
|
10
|
+
unused: [],
|
|
11
|
+
prefixes: [],
|
|
12
|
+
patterns: []
|
|
11
13
|
},
|
|
12
14
|
policy: {
|
|
13
15
|
minScore: 0,
|
|
@@ -24,6 +26,9 @@ export const defaultConfig = {
|
|
|
24
26
|
outdatedWeight: 3,
|
|
25
27
|
unusedWeight: 4,
|
|
26
28
|
riskWeight: 10
|
|
29
|
+
},
|
|
30
|
+
scan: {
|
|
31
|
+
excludePaths: ["node_modules", "dist", "build", "coverage", ".git"]
|
|
27
32
|
}
|
|
28
33
|
};
|
|
29
34
|
export async function loadDepBrainConfig(rootDir, configPath) {
|
|
@@ -44,7 +49,9 @@ function normalizeConfig(loaded) {
|
|
|
44
49
|
duplicates: normalizeStringArray(loaded.ignore?.duplicates, defaultConfig.ignore.duplicates),
|
|
45
50
|
outdated: normalizeStringArray(loaded.ignore?.outdated, defaultConfig.ignore.outdated),
|
|
46
51
|
risks: normalizeStringArray(loaded.ignore?.risks, defaultConfig.ignore.risks),
|
|
47
|
-
unused: normalizeStringArray(loaded.ignore?.unused, defaultConfig.ignore.unused)
|
|
52
|
+
unused: normalizeStringArray(loaded.ignore?.unused, defaultConfig.ignore.unused),
|
|
53
|
+
prefixes: normalizeStringArray(loaded.ignore?.prefixes, defaultConfig.ignore.prefixes),
|
|
54
|
+
patterns: normalizeStringArray(loaded.ignore?.patterns, defaultConfig.ignore.patterns)
|
|
48
55
|
},
|
|
49
56
|
policy: {
|
|
50
57
|
minScore: normalizeNumber(loaded.policy?.minScore, defaultConfig.policy.minScore),
|
|
@@ -61,6 +68,9 @@ function normalizeConfig(loaded) {
|
|
|
61
68
|
outdatedWeight: normalizeNumber(loaded.scoring?.outdatedWeight, defaultConfig.scoring.outdatedWeight),
|
|
62
69
|
unusedWeight: normalizeNumber(loaded.scoring?.unusedWeight, defaultConfig.scoring.unusedWeight),
|
|
63
70
|
riskWeight: normalizeNumber(loaded.scoring?.riskWeight, defaultConfig.scoring.riskWeight)
|
|
71
|
+
},
|
|
72
|
+
scan: {
|
|
73
|
+
excludePaths: normalizeStringArray(loaded.scan?.excludePaths, defaultConfig.scan.excludePaths)
|
|
64
74
|
}
|
|
65
75
|
};
|
|
66
76
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare function readJsonFile<T>(filePath: string): Promise<T>;
|
|
2
2
|
export declare function readTextFile(filePath: string): Promise<string>;
|
|
3
|
-
export declare function collectProjectFiles(rootDir: string, pattern: RegExp): Promise<string[]>;
|
|
3
|
+
export declare function collectProjectFiles(rootDir: string, pattern: RegExp, excludePaths?: string[]): Promise<string[]>;
|
|
@@ -7,16 +7,23 @@ export async function readJsonFile(filePath) {
|
|
|
7
7
|
export async function readTextFile(filePath) {
|
|
8
8
|
return fs.readFile(filePath, "utf8");
|
|
9
9
|
}
|
|
10
|
-
export async function collectProjectFiles(rootDir, pattern) {
|
|
11
|
-
|
|
10
|
+
export async function collectProjectFiles(rootDir, pattern, excludePaths = []) {
|
|
11
|
+
return collectProjectFilesInternal(rootDir, rootDir, pattern, excludePaths);
|
|
12
|
+
}
|
|
13
|
+
async function collectProjectFilesInternal(currentDir, baseDir, pattern, excludePaths) {
|
|
14
|
+
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
12
15
|
const files = [];
|
|
13
16
|
for (const entry of entries) {
|
|
14
|
-
const fullPath = path.join(
|
|
17
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
18
|
+
const relPath = path.relative(baseDir, fullPath);
|
|
19
|
+
if (matchesAnyPattern(relPath, excludePaths)) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
15
22
|
if (entry.isDirectory()) {
|
|
16
23
|
if (entry.name === ".git") {
|
|
17
24
|
continue;
|
|
18
25
|
}
|
|
19
|
-
files.push(...(await
|
|
26
|
+
files.push(...(await collectProjectFilesInternal(fullPath, baseDir, pattern, excludePaths)));
|
|
20
27
|
continue;
|
|
21
28
|
}
|
|
22
29
|
if (pattern.test(entry.name)) {
|
|
@@ -25,3 +32,26 @@ export async function collectProjectFiles(rootDir, pattern) {
|
|
|
25
32
|
}
|
|
26
33
|
return files;
|
|
27
34
|
}
|
|
35
|
+
function matchesAnyPattern(value, patterns) {
|
|
36
|
+
if (patterns.length === 0) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const normalized = normalizePath(value);
|
|
40
|
+
return patterns.some((pattern) => {
|
|
41
|
+
const regex = globToRegExp(pattern);
|
|
42
|
+
return regex.test(normalized);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function globToRegExp(pattern) {
|
|
46
|
+
const normalized = normalizePath(pattern)
|
|
47
|
+
.replace(/\/+$/, "")
|
|
48
|
+
.replace(/^\//, "")
|
|
49
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
50
|
+
.replace(/\*\*/g, "___DEPBRAIN_GLOBSTAR___")
|
|
51
|
+
.replace(/\*/g, "[^/]*")
|
|
52
|
+
.replace(/___DEPBRAIN_GLOBSTAR___/g, ".*");
|
|
53
|
+
return new RegExp(`(^|.*/)${normalized}($|/.*)`);
|
|
54
|
+
}
|
|
55
|
+
function normalizePath(value) {
|
|
56
|
+
return value.split(path.sep).join("/");
|
|
57
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dep-brain",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "CLI and library for dependency health analysis",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"LICENSE",
|
|
15
15
|
"CHANGELOG.md",
|
|
16
16
|
"depbrain.config.json",
|
|
17
|
-
"depbrain.config.schema.json"
|
|
17
|
+
"depbrain.config.schema.json",
|
|
18
|
+
"depbrain.output.schema.json"
|
|
18
19
|
],
|
|
19
20
|
"scripts": {
|
|
20
21
|
"build": "tsc -p tsconfig.json",
|