Skip to content

Commit d5d41ca

Browse files
author
Dan Clayton
committed
docs(changeset): add debug
1 parent a917dd6 commit d5d41ca

8 files changed

Lines changed: 161 additions & 14 deletions

File tree

.changeset/nine-carrots-turn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@azwebmaster/dependency-optimizer": patch
3+
---
4+
5+
add debug

bun.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@
3333
},
3434
"dependencies": {
3535
"commander": "^12.1.0",
36+
"debug": "^4.4.3",
3637
"depcheck": "^1.4.7",
3738
"globby": "^14.0.1"
3839
},
3940
"devDependencies": {
4041
"@changesets/cli": "^2.29.7",
42+
"@types/debug": "^4.1.12",
4143
"@types/node": "latest",
4244
"@vitest/coverage-v8": "^3.2.4",
4345
"@vitest/ui": "^3.2.4",

src/analyzer.ts

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
import * as fs from 'fs/promises';
22
import * as path from 'path';
33
import type { AnalyzeOptions, AnalyzeResult, PackageAnalysis } from './types.js';
4+
import createDebug from 'debug';
5+
6+
const debug = createDebug('depoptimize:analyzer');
47

58
export class NodeModulesAnalyzer {
69
constructor(private options: AnalyzeOptions = {}) {}
710

811
async analyze(projectPath: string = process.cwd()): Promise<AnalyzeResult> {
12+
debug('Starting analysis for project: %s', projectPath);
913
const nodeModulesPath = path.join(projectPath, 'node_modules');
1014
const sizeThreshold = (this.options.sizeThreshold || 10) * 1024 * 1024; // Convert MB to bytes
1115
const depthThreshold = this.options.depthThreshold || 5;
16+
debug('Configuration - sizeThreshold: %d bytes, depthThreshold: %d', sizeThreshold, depthThreshold);
1217

1318
const result: AnalyzeResult = {
1419
totalPackages: 0,
@@ -22,43 +27,53 @@ export class NodeModulesAnalyzer {
2227
// Check if node_modules exists
2328
const nodeModulesExists = await this.directoryExists(nodeModulesPath);
2429
if (!nodeModulesExists) {
30+
debug('node_modules not found at: %s', nodeModulesPath);
2531
return result;
2632
}
33+
debug('Found node_modules at: %s', nodeModulesPath);
2734

2835
// Get all packages in node_modules
2936
const packages = await this.getAllPackages(nodeModulesPath);
3037
result.totalPackages = packages.length;
38+
debug('Found %d packages in node_modules', packages.length);
3139

3240
// Analyze each package
3341
for (const pkg of packages) {
42+
debug('Analyzing package: %s', pkg.name);
3443
const analysis = await this.analyzePackage(pkg.path, pkg.name);
3544

3645
result.totalSize += analysis.size;
3746

3847
// Check if package exceeds size threshold
3948
if (analysis.size > sizeThreshold) {
49+
debug('Large package detected: %s (%d bytes)', pkg.name, analysis.size);
4050
result.largePackages.push(analysis);
4151
}
4252

4353
// Check if package exceeds depth threshold
4454
if (analysis.depth > depthThreshold) {
55+
debug('Deep package detected: %s (depth: %d)', pkg.name, analysis.depth);
4556
result.deepPackages.push(analysis);
4657
}
4758
}
4859

4960
// Sort results by size/depth descending
5061
result.largePackages.sort((a, b) => b.size - a.size);
5162
result.deepPackages.sort((a, b) => b.depth - a.depth);
63+
debug('Analysis complete - total size: %d bytes, large packages: %d, deep packages: %d',
64+
result.totalSize, result.largePackages.length, result.deepPackages.length);
5265

5366
} catch (error) {
5467
// Handle errors gracefully
68+
debug('Error during analysis: %O', error);
5569
console.warn(`Warning: Failed to analyze node_modules: ${error}`);
5670
}
5771

5872
return result;
5973
}
6074

6175
private async getAllPackages(nodeModulesPath: string): Promise<{ name: string; path: string }[]> {
76+
debug('Scanning for packages in: %s', nodeModulesPath);
6277
const packages: { name: string; path: string }[] = [];
6378

6479
try {
@@ -70,6 +85,7 @@ export class NodeModulesAnalyzer {
7085

7186
if (entry.name.startsWith('@')) {
7287
// Scoped packages
88+
debug('Processing scoped package directory: %s', entry.name);
7389
try {
7490
const scopedEntries = await fs.readdir(entryPath, { withFileTypes: true });
7591
for (const scopedEntry of scopedEntries) {
@@ -79,25 +95,30 @@ export class NodeModulesAnalyzer {
7995

8096
// Verify it's a valid package
8197
if (await this.isValidPackage(scopedPath)) {
98+
debug('Found scoped package: %s', packageName);
8299
packages.push({ name: packageName, path: scopedPath });
83100
}
84101
}
85102
}
86-
} catch {
103+
} catch (error) {
87104
// Skip if can't read scoped directory
105+
debug('Failed to read scoped directory %s: %O', entry.name, error);
88106
}
89107
} else {
90108
// Regular packages
91109
if (await this.isValidPackage(entryPath)) {
110+
debug('Found package: %s', entry.name);
92111
packages.push({ name: entry.name, path: entryPath });
93112
}
94113
}
95114
}
96115
}
97-
} catch {
116+
} catch (error) {
98117
// Return empty array if can't read node_modules
118+
debug('Failed to read node_modules directory: %O', error);
99119
}
100120

121+
debug('Total packages found: %d', packages.length);
101122
return packages;
102123
}
103124

@@ -112,6 +133,7 @@ export class NodeModulesAnalyzer {
112133
}
113134

114135
private async analyzePackage(packagePath: string, packageName: string): Promise<PackageAnalysis> {
136+
debug('Analyzing package details for: %s', packageName);
115137
const analysis: PackageAnalysis = {
116138
name: packageName,
117139
size: 0,
@@ -122,18 +144,22 @@ export class NodeModulesAnalyzer {
122144
try {
123145
// Calculate package size
124146
analysis.size = await this.getDirectorySize(packagePath);
147+
debug('Package %s size: %d bytes', packageName, analysis.size);
125148

126149
// Calculate dependency depth
127150
analysis.depth = await this.getDependencyDepth(packagePath);
151+
debug('Package %s depth: %d', packageName, analysis.depth);
128152

129-
} catch {
153+
} catch (error) {
130154
// If we can't analyze, just return default values
155+
debug('Failed to analyze package %s: %O', packageName, error);
131156
}
132157

133158
return analysis;
134159
}
135160

136161
private async getDirectorySize(dirPath: string): Promise<number> {
162+
debug('Calculating size for directory: %s', dirPath);
137163
let size = 0;
138164

139165
try {
@@ -145,31 +171,37 @@ export class NodeModulesAnalyzer {
145171
if (entry.isDirectory()) {
146172
// Skip nested node_modules to avoid double counting
147173
if (entry.name === 'node_modules') {
174+
debug('Skipping nested node_modules in: %s', dirPath);
148175
continue;
149176
}
150177
size += await this.getDirectorySize(entryPath);
151178
} else if (entry.isFile()) {
152179
try {
153180
const stats = await fs.stat(entryPath);
154181
size += stats.size;
155-
} catch {
182+
} catch (error) {
156183
// Skip files we can't read
184+
debug('Failed to read file %s: %O', entryPath, error);
157185
}
158186
}
159187
}
160-
} catch {
188+
} catch (error) {
161189
// Return 0 if we can't read the directory
190+
debug('Failed to read directory %s: %O', dirPath, error);
162191
}
163192

193+
debug('Total size for %s: %d bytes', dirPath, size);
164194
return size;
165195
}
166196

167197
private async getDependencyDepth(packagePath: string, visited = new Set<string>()): Promise<number> {
168198
// Prevent infinite recursion
169199
if (visited.has(packagePath)) {
200+
debug('Circular dependency detected, skipping: %s', packagePath);
170201
return 0;
171202
}
172203
visited.add(packagePath);
204+
debug('Calculating depth for: %s', packagePath);
173205

174206
try {
175207
const packageJsonPath = path.join(packagePath, 'package.json');
@@ -182,14 +214,17 @@ export class NodeModulesAnalyzer {
182214
};
183215

184216
if (!dependencies || Object.keys(dependencies).length === 0) {
217+
debug('No dependencies found for: %s', packagePath);
185218
return 0;
186219
}
220+
debug('Found %d dependencies for: %s', Object.keys(dependencies).length, packagePath);
187221

188222
let maxDepth = 0;
189223
const nodeModulesPath = path.join(packagePath, 'node_modules');
190224

191225
// Check if this package has its own node_modules
192226
if (await this.directoryExists(nodeModulesPath)) {
227+
debug('Checking nested node_modules: %s', nodeModulesPath);
193228
for (const depName of Object.keys(dependencies)) {
194229
const depPath = await this.findDependencyPath(nodeModulesPath, depName);
195230
if (depPath) {
@@ -199,27 +234,33 @@ export class NodeModulesAnalyzer {
199234
}
200235
}
201236

237+
debug('Max depth for %s: %d', packagePath, maxDepth);
202238
return maxDepth;
203239

204-
} catch {
240+
} catch (error) {
241+
debug('Failed to calculate depth for %s: %O', packagePath, error);
205242
return 0;
206243
}
207244
}
208245

209246
private async findDependencyPath(nodeModulesPath: string, depName: string): Promise<string | null> {
247+
debug('Looking for dependency %s in %s', depName, nodeModulesPath);
210248
// Check for scoped package
211249
if (depName.includes('/')) {
212250
const depPath = path.join(nodeModulesPath, depName);
213251
if (await this.directoryExists(depPath)) {
252+
debug('Found scoped dependency at: %s', depPath);
214253
return depPath;
215254
}
216255
} else {
217256
const depPath = path.join(nodeModulesPath, depName);
218257
if (await this.directoryExists(depPath)) {
258+
debug('Found dependency at: %s', depPath);
219259
return depPath;
220260
}
221261
}
222262

263+
debug('Dependency %s not found in %s', depName, nodeModulesPath);
223264
return null;
224265
}
225266

0 commit comments

Comments
 (0)