@manojkmfsi/monodog 1.0.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.
- package/.eslintrc.cjs +15 -0
- package/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +79 -0
- package/LICENCE +21 -0
- package/README.md +55 -0
- package/dist/config-loader.js +116 -0
- package/dist/get-db-url.js +10 -0
- package/dist/gitService.js +242 -0
- package/dist/index.js +1370 -0
- package/dist/serve.js +103 -0
- package/dist/setup.js +155 -0
- package/dist/utils/ci-status.js +446 -0
- package/dist/utils/helpers.js +237 -0
- package/dist/utils/monorepo-scanner.js +486 -0
- package/dist/utils/utilities.js +414 -0
- package/monodog-conf.example.json +16 -0
- package/monodog-conf.json +16 -0
- package/monodog-dashboard/README.md +58 -0
- package/monodog-dashboard/dist/assets/index-2d967652.js +71 -0
- package/monodog-dashboard/dist/assets/index-504dc418.css +1 -0
- package/monodog-dashboard/dist/index.html +15 -0
- package/package.json +50 -0
- package/prisma/migrations/20251017041048_init/migration.sql +19 -0
- package/prisma/migrations/20251017083007_add_package/migration.sql +21 -0
- package/prisma/migrations/20251021083705_alter_package/migration.sql +37 -0
- package/prisma/migrations/20251022085155_test/migration.sql +2 -0
- package/prisma/migrations/20251022160841_/migration.sql +35 -0
- package/prisma/migrations/20251023130158_rename_column_name/migration.sql +34 -0
- package/prisma/migrations/20251023174837_/migration.sql +34 -0
- package/prisma/migrations/20251023175830_uodate_schema/migration.sql +32 -0
- package/prisma/migrations/20251024103700_add_dependency_info/migration.sql +13 -0
- package/prisma/migrations/20251025192150_add_dependency_info/migration.sql +19 -0
- package/prisma/migrations/20251025192342_add_dependency_info/migration.sql +40 -0
- package/prisma/migrations/20251025204613_add_dependency_info/migration.sql +8 -0
- package/prisma/migrations/20251026071336_add_dependency_info/migration.sql +25 -0
- package/prisma/migrations/20251027062626_add_commit/migration.sql +10 -0
- package/prisma/migrations/20251027062748_add_commit/migration.sql +23 -0
- package/prisma/migrations/20251027092741_add_commit/migration.sql +17 -0
- package/prisma/migrations/20251027112736_add_health_status/migration.sql +16 -0
- package/prisma/migrations/20251027140546_init_packages/migration.sql +16 -0
- package/prisma/migrations/20251029073436_added_package_heath_key/migration.sql +34 -0
- package/prisma/migrations/20251029073830_added_package_health_key/migration.sql +49 -0
- package/prisma/migrations/20251111091920_/migration.sql +16 -0
- package/prisma/migrations/20251211155036_cascade_on_auto_delete/migration.sql +48 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +114 -0
- package/release.config.js +41 -0
- package/src/config-loader.ts +119 -0
- package/src/get-db-url.ts +11 -0
- package/src/gitService.ts +277 -0
- package/src/index.ts +1554 -0
- package/src/serve.ts +87 -0
- package/src/setup.ts +164 -0
- package/src/types/monorepo-scanner.d.ts +32 -0
- package/src/utils/ci-status.ts +639 -0
- package/src/utils/helpers.js +203 -0
- package/src/utils/helpers.js.map +1 -0
- package/src/utils/helpers.ts +238 -0
- package/src/utils/monorepo-scanner.ts +599 -0
- package/src/utils/utilities.ts +483 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.scanner = exports.MonorepoScanner = void 0;
|
|
7
|
+
exports.quickScan = quickScan;
|
|
8
|
+
exports.generateReports = generateReports;
|
|
9
|
+
exports.scanForFiles = scanForFiles;
|
|
10
|
+
exports.funCheckBuildStatus = funCheckBuildStatus;
|
|
11
|
+
exports.funCheckTestCoverage = funCheckTestCoverage;
|
|
12
|
+
exports.funCheckLintStatus = funCheckLintStatus;
|
|
13
|
+
exports.funCheckSecurityAudit = funCheckSecurityAudit;
|
|
14
|
+
// Monorepo Scanner
|
|
15
|
+
const fs_1 = __importDefault(require("fs"));
|
|
16
|
+
const path_1 = __importDefault(require("path"));
|
|
17
|
+
const child_process_1 = require("child_process");
|
|
18
|
+
const utilities_1 = require("./utilities");
|
|
19
|
+
class MonorepoScanner {
|
|
20
|
+
constructor(rootDir = process.cwd()) {
|
|
21
|
+
this.cache = new Map();
|
|
22
|
+
this.cacheExpiry = 5 * 60 * 1000; // 5 minutes
|
|
23
|
+
this.rootDir = rootDir;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Performs a complete scan of the monorepo
|
|
27
|
+
*/
|
|
28
|
+
async scan() {
|
|
29
|
+
const startTime = Date.now();
|
|
30
|
+
try {
|
|
31
|
+
// Check cache first
|
|
32
|
+
const cacheKey = 'full-scan';
|
|
33
|
+
const cached = this.getFromCache(cacheKey);
|
|
34
|
+
if (cached) {
|
|
35
|
+
return cached;
|
|
36
|
+
}
|
|
37
|
+
console.log('🔍 Starting monorepo scan...');
|
|
38
|
+
// Scan all packages
|
|
39
|
+
const packages = (0, utilities_1.scanMonorepo)(this.rootDir);
|
|
40
|
+
console.log(`📦 Found ${packages.length} packages`);
|
|
41
|
+
// Generate statistics
|
|
42
|
+
const stats = (0, utilities_1.generateMonorepoStats)(packages);
|
|
43
|
+
// Generate dependency graph
|
|
44
|
+
const dependencyGraph = (0, utilities_1.generateDependencyGraph)(packages);
|
|
45
|
+
// Find circular dependencies
|
|
46
|
+
const circularDependencies = (0, utilities_1.findCircularDependencies)(packages);
|
|
47
|
+
// Check for outdated packages
|
|
48
|
+
const outdatedPackages = this.findOutdatedPackages(packages);
|
|
49
|
+
const result = {
|
|
50
|
+
packages,
|
|
51
|
+
stats,
|
|
52
|
+
dependencyGraph,
|
|
53
|
+
circularDependencies,
|
|
54
|
+
outdatedPackages,
|
|
55
|
+
scanTimestamp: new Date(),
|
|
56
|
+
scanDuration: Date.now() - startTime,
|
|
57
|
+
};
|
|
58
|
+
// Cache the result
|
|
59
|
+
this.setCache(cacheKey, result);
|
|
60
|
+
console.log(`✅ Scan completed in ${result.scanDuration}ms`);
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
console.error('❌ Error during scan:', error);
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Generates detailed reports for all packages
|
|
70
|
+
*/
|
|
71
|
+
async generatePackageReports() {
|
|
72
|
+
const packages = (0, utilities_1.scanMonorepo)(this.rootDir);
|
|
73
|
+
const reports = [];
|
|
74
|
+
for (const pkg of packages) {
|
|
75
|
+
try {
|
|
76
|
+
const report = await this.generatePackageReport(pkg);
|
|
77
|
+
reports.push(report);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error(`Error generating report for ${pkg.name}:`, error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return reports;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Generates a detailed report for a specific package
|
|
87
|
+
*/
|
|
88
|
+
async generatePackageReport(pkg) {
|
|
89
|
+
const health = await this.assessPackageHealth(pkg);
|
|
90
|
+
const size = (0, utilities_1.getPackageSize)(pkg.path);
|
|
91
|
+
const outdatedDeps = (0, utilities_1.checkOutdatedDependencies)(pkg);
|
|
92
|
+
const lastModified = this.getLastModified(pkg.path);
|
|
93
|
+
const gitInfo = await this.getGitInfo(pkg.path);
|
|
94
|
+
return {
|
|
95
|
+
package: pkg,
|
|
96
|
+
health,
|
|
97
|
+
size,
|
|
98
|
+
outdatedDeps,
|
|
99
|
+
lastModified,
|
|
100
|
+
gitInfo,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Assesses the health of a package
|
|
105
|
+
*/
|
|
106
|
+
async assessPackageHealth(pkg) {
|
|
107
|
+
// Check build status
|
|
108
|
+
const buildStatus = await this.checkBuildStatus(pkg);
|
|
109
|
+
// Check test coverage
|
|
110
|
+
const testCoverage = await this.checkTestCoverage(pkg);
|
|
111
|
+
// Check lint status
|
|
112
|
+
const lintStatus = await this.checkLintStatus(pkg);
|
|
113
|
+
// Check security audit
|
|
114
|
+
const securityAudit = await this.checkSecurityAudit(pkg);
|
|
115
|
+
return (0, utilities_1.calculatePackageHealth)(buildStatus, testCoverage, lintStatus, securityAudit);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Checks if a package builds successfully
|
|
119
|
+
*/
|
|
120
|
+
async checkBuildStatus(pkg) {
|
|
121
|
+
try {
|
|
122
|
+
if (pkg.scripts.build) {
|
|
123
|
+
// Try to run build command
|
|
124
|
+
(0, child_process_1.execSync)('npm run build', {
|
|
125
|
+
cwd: pkg.path,
|
|
126
|
+
stdio: 'pipe',
|
|
127
|
+
timeout: 30000,
|
|
128
|
+
});
|
|
129
|
+
return 'success';
|
|
130
|
+
}
|
|
131
|
+
return 'unknown';
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
return 'failed';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Checks test coverage for a package
|
|
139
|
+
*/
|
|
140
|
+
// async checkTestCoverage(pkg: PackageInfo): Promise<number> {
|
|
141
|
+
// try {
|
|
142
|
+
// if (pkg.scripts.test) {
|
|
143
|
+
// // This would typically run tests and parse coverage reports
|
|
144
|
+
// // For now, return a mock value
|
|
145
|
+
// return Math.floor(Math.random() * 100);
|
|
146
|
+
// }
|
|
147
|
+
// return 0;
|
|
148
|
+
// } catch (error) {
|
|
149
|
+
// return 0;
|
|
150
|
+
// }
|
|
151
|
+
// }
|
|
152
|
+
async checkTestCoverage(pkg) {
|
|
153
|
+
try {
|
|
154
|
+
// First, check for existing coverage reports
|
|
155
|
+
const coveragePaths = [
|
|
156
|
+
path_1.default.join(pkg.path, 'coverage', 'coverage-summary.json'),
|
|
157
|
+
path_1.default.join(pkg.path, 'coverage', 'lcov.info'),
|
|
158
|
+
path_1.default.join(pkg.path, 'coverage', 'clover.xml'),
|
|
159
|
+
path_1.default.join(pkg.path, 'coverage.json'),
|
|
160
|
+
];
|
|
161
|
+
// Look for any coverage file that exists
|
|
162
|
+
for (const coveragePath of coveragePaths) {
|
|
163
|
+
if (fs_1.default.existsSync(coveragePath)) {
|
|
164
|
+
if (coveragePath.endsWith('coverage-summary.json')) {
|
|
165
|
+
try {
|
|
166
|
+
const coverage = JSON.parse(fs_1.default.readFileSync(coveragePath, 'utf8'));
|
|
167
|
+
return (coverage.total?.lines?.pct ||
|
|
168
|
+
coverage.total?.statements?.pct ||
|
|
169
|
+
0);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
console.warn(`Error parsing coverage file for ${pkg.name}:`, error);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// If we find any coverage file but can't parse it, assume coverage exists
|
|
176
|
+
return 50; // Default coverage if files exist but can't parse
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// If no coverage files found and package has test script
|
|
180
|
+
if (pkg.scripts.test) {
|
|
181
|
+
// Return a reasonable default based on whether tests are likely to have coverage
|
|
182
|
+
const hasCoverageSetup = pkg.scripts.test.includes('--coverage') ||
|
|
183
|
+
pkg.scripts.test.includes('coverage') ||
|
|
184
|
+
pkg.devDependencies?.jest ||
|
|
185
|
+
pkg.devDependencies?.nyc ||
|
|
186
|
+
pkg.devDependencies?.['@types/jest'];
|
|
187
|
+
return hasCoverageSetup ? 30 : 0; // Reasonable defaults
|
|
188
|
+
}
|
|
189
|
+
return 0;
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
console.warn(`Error checking coverage for ${pkg.name}:`, error);
|
|
193
|
+
return 0;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Checks lint status for a package
|
|
198
|
+
*/
|
|
199
|
+
async checkLintStatus(pkg) {
|
|
200
|
+
try {
|
|
201
|
+
if (pkg.scripts.lint) {
|
|
202
|
+
// Try to run lint command
|
|
203
|
+
(0, child_process_1.execSync)('npm run lint', {
|
|
204
|
+
cwd: pkg.path,
|
|
205
|
+
stdio: 'pipe',
|
|
206
|
+
timeout: 10000,
|
|
207
|
+
});
|
|
208
|
+
return 'pass';
|
|
209
|
+
}
|
|
210
|
+
return 'unknown';
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
return 'fail';
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Checks security audit for a package
|
|
218
|
+
*/
|
|
219
|
+
async checkSecurityAudit(pkg) {
|
|
220
|
+
try {
|
|
221
|
+
// Run npm audit
|
|
222
|
+
const result = (0, child_process_1.execSync)('npm audit --json', {
|
|
223
|
+
cwd: pkg.path,
|
|
224
|
+
stdio: 'pipe',
|
|
225
|
+
timeout: 15000,
|
|
226
|
+
});
|
|
227
|
+
const audit = JSON.parse(result.toString());
|
|
228
|
+
return audit.metadata.vulnerabilities.total === 0 ? 'pass' : 'fail';
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
return 'unknown';
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Finds packages with outdated dependencies
|
|
236
|
+
*/
|
|
237
|
+
findOutdatedPackages(packages) {
|
|
238
|
+
const outdated = [];
|
|
239
|
+
for (const pkg of packages) {
|
|
240
|
+
const outdatedDeps = (0, utilities_1.checkOutdatedDependencies)(pkg);
|
|
241
|
+
if (outdatedDeps.length > 0) {
|
|
242
|
+
outdated.push(pkg.name);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return outdated;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Gets the last modified date of a package
|
|
249
|
+
*/
|
|
250
|
+
getLastModified(packagePath) {
|
|
251
|
+
try {
|
|
252
|
+
const stats = fs_1.default.statSync(packagePath);
|
|
253
|
+
return stats.mtime;
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
return new Date();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Gets git information for a package
|
|
261
|
+
*/
|
|
262
|
+
async getGitInfo(packagePath) {
|
|
263
|
+
try {
|
|
264
|
+
// Check if this is a git repository
|
|
265
|
+
const gitPath = path_1.default.join(packagePath, '.git');
|
|
266
|
+
if (!fs_1.default.existsSync(gitPath)) {
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
// Get last commit info
|
|
270
|
+
const lastCommit = (0, child_process_1.execSync)('git rev-parse HEAD', {
|
|
271
|
+
cwd: packagePath,
|
|
272
|
+
stdio: 'pipe',
|
|
273
|
+
})
|
|
274
|
+
.toString()
|
|
275
|
+
.trim();
|
|
276
|
+
const lastCommitDate = new Date((0, child_process_1.execSync)('git log -1 --format=%cd', {
|
|
277
|
+
cwd: packagePath,
|
|
278
|
+
stdio: 'pipe',
|
|
279
|
+
})
|
|
280
|
+
.toString()
|
|
281
|
+
.trim());
|
|
282
|
+
const author = (0, child_process_1.execSync)('git log -1 --format=%an', {
|
|
283
|
+
cwd: packagePath,
|
|
284
|
+
stdio: 'pipe',
|
|
285
|
+
})
|
|
286
|
+
.toString()
|
|
287
|
+
.trim();
|
|
288
|
+
const branch = (0, child_process_1.execSync)('git branch --show-current', {
|
|
289
|
+
cwd: packagePath,
|
|
290
|
+
stdio: 'pipe',
|
|
291
|
+
})
|
|
292
|
+
.toString()
|
|
293
|
+
.trim();
|
|
294
|
+
return {
|
|
295
|
+
lastCommit: lastCommit.substring(0, 7),
|
|
296
|
+
lastCommitDate,
|
|
297
|
+
author,
|
|
298
|
+
branch,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Scans for specific file types in packages
|
|
307
|
+
*/
|
|
308
|
+
scanForFileTypes(fileTypes) {
|
|
309
|
+
const results = {};
|
|
310
|
+
for (const fileType of fileTypes) {
|
|
311
|
+
results[fileType] = [];
|
|
312
|
+
}
|
|
313
|
+
const packages = (0, utilities_1.scanMonorepo)(this.rootDir);
|
|
314
|
+
for (const pkg of packages) {
|
|
315
|
+
this.scanPackageForFiles(pkg.path, fileTypes, results);
|
|
316
|
+
}
|
|
317
|
+
return results;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Recursively scans a package directory for specific file types
|
|
321
|
+
*/
|
|
322
|
+
scanPackageForFiles(packagePath, fileTypes, results) {
|
|
323
|
+
try {
|
|
324
|
+
const items = fs_1.default.readdirSync(packagePath, { withFileTypes: true });
|
|
325
|
+
for (const item of items) {
|
|
326
|
+
const fullPath = path_1.default.join(packagePath, item.name);
|
|
327
|
+
if (item.isDirectory()) {
|
|
328
|
+
// Skip certain directories
|
|
329
|
+
if (!['node_modules', 'dist', 'build', '.git'].includes(item.name)) {
|
|
330
|
+
this.scanPackageForFiles(fullPath, fileTypes, results);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
// Check file extension
|
|
335
|
+
const ext = path_1.default.extname(item.name);
|
|
336
|
+
if (fileTypes.includes(ext)) {
|
|
337
|
+
results[ext].push(fullPath);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
// Skip directories we can't read
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Gets cache value if not expired
|
|
348
|
+
*/
|
|
349
|
+
getFromCache(key) {
|
|
350
|
+
const cached = this.cache.get(key);
|
|
351
|
+
if (cached && Date.now() - cached.timestamp < this.cacheExpiry) {
|
|
352
|
+
return cached.data;
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Sets cache value with timestamp
|
|
358
|
+
*/
|
|
359
|
+
setCache(key, data) {
|
|
360
|
+
this.cache.set(key, {
|
|
361
|
+
data,
|
|
362
|
+
timestamp: Date.now(),
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Clears the cache
|
|
367
|
+
*/
|
|
368
|
+
clearCache() {
|
|
369
|
+
this.cache.clear();
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Exports scan results to various formats
|
|
373
|
+
*/
|
|
374
|
+
exportResults(results, format) {
|
|
375
|
+
switch (format) {
|
|
376
|
+
case 'json':
|
|
377
|
+
return JSON.stringify(results, null, 2);
|
|
378
|
+
case 'csv':
|
|
379
|
+
return this.exportToCSV(results);
|
|
380
|
+
case 'html':
|
|
381
|
+
return this.exportToHTML(results);
|
|
382
|
+
default:
|
|
383
|
+
throw new Error(`Unsupported format: ${format}`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Exports results to CSV format
|
|
388
|
+
*/
|
|
389
|
+
exportToCSV(results) {
|
|
390
|
+
const headers = [
|
|
391
|
+
'Package',
|
|
392
|
+
'Type',
|
|
393
|
+
'Version',
|
|
394
|
+
'Dependencies',
|
|
395
|
+
'Health Score',
|
|
396
|
+
];
|
|
397
|
+
const rows = results.packages.map(pkg => [
|
|
398
|
+
pkg.name,
|
|
399
|
+
pkg.type,
|
|
400
|
+
pkg.version,
|
|
401
|
+
Object.keys(pkg.dependencies).length,
|
|
402
|
+
'N/A', // Would need health calculation
|
|
403
|
+
]);
|
|
404
|
+
return [headers, ...rows]
|
|
405
|
+
.map(row => row.map(cell => `"${cell}"`).join(','))
|
|
406
|
+
.join('\n');
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Exports results to HTML format
|
|
410
|
+
*/
|
|
411
|
+
exportToHTML(results) {
|
|
412
|
+
return `
|
|
413
|
+
<!DOCTYPE html>
|
|
414
|
+
<html>
|
|
415
|
+
<head>
|
|
416
|
+
<title>Monorepo Scan Report</title>
|
|
417
|
+
<style>
|
|
418
|
+
body { font-family: Arial, sans-serif; margin: 20px; }
|
|
419
|
+
table { border-collapse: collapse; width: 100%; }
|
|
420
|
+
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
|
421
|
+
th { background-color: #f2f2f2; }
|
|
422
|
+
</style>
|
|
423
|
+
</head>
|
|
424
|
+
<body>
|
|
425
|
+
<h1>Monorepo Scan Report</h1>
|
|
426
|
+
<p>Generated: ${results.scanTimestamp}</p>
|
|
427
|
+
<p>Duration: ${results.scanDuration}ms</p>
|
|
428
|
+
|
|
429
|
+
<h2>Summary</h2>
|
|
430
|
+
<ul>
|
|
431
|
+
<li>Total Packages: ${results.stats.totalPackages}</li>
|
|
432
|
+
<li>Applications: ${results.stats.apps}</li>
|
|
433
|
+
<li>Libraries: ${results.stats.libraries}</li>
|
|
434
|
+
<li>Tools: ${results.stats.tools}</li>
|
|
435
|
+
</ul>
|
|
436
|
+
|
|
437
|
+
<h2>Packages</h2>
|
|
438
|
+
<table>
|
|
439
|
+
<tr>
|
|
440
|
+
<th>Name</th>
|
|
441
|
+
<th>Type</th>
|
|
442
|
+
<th>Version</th>
|
|
443
|
+
<th>Dependencies</th>
|
|
444
|
+
</tr>
|
|
445
|
+
${results.packages
|
|
446
|
+
.map(pkg => `
|
|
447
|
+
<tr>
|
|
448
|
+
<td>${pkg.name}</td>
|
|
449
|
+
<td>${pkg.type}</td>
|
|
450
|
+
<td>${pkg.version}</td>
|
|
451
|
+
<td>${Object.keys(pkg.dependencies).length}</td>
|
|
452
|
+
</tr>
|
|
453
|
+
`)
|
|
454
|
+
.join('')}
|
|
455
|
+
</table>
|
|
456
|
+
</body>
|
|
457
|
+
</html>
|
|
458
|
+
`;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
exports.MonorepoScanner = MonorepoScanner;
|
|
462
|
+
// Export default instance
|
|
463
|
+
exports.scanner = new MonorepoScanner();
|
|
464
|
+
// Export convenience functions
|
|
465
|
+
async function quickScan() {
|
|
466
|
+
return exports.scanner.scan();
|
|
467
|
+
}
|
|
468
|
+
async function generateReports() {
|
|
469
|
+
return exports.scanner.generatePackageReports();
|
|
470
|
+
}
|
|
471
|
+
function scanForFiles(fileTypes) {
|
|
472
|
+
return exports.scanner.scanForFileTypes(fileTypes);
|
|
473
|
+
}
|
|
474
|
+
// Fix these function signatures - they should accept single PackageInfo objects
|
|
475
|
+
async function funCheckBuildStatus(pkg) {
|
|
476
|
+
return exports.scanner.checkBuildStatus(pkg);
|
|
477
|
+
}
|
|
478
|
+
async function funCheckTestCoverage(pkg) {
|
|
479
|
+
return exports.scanner.checkTestCoverage(pkg);
|
|
480
|
+
}
|
|
481
|
+
async function funCheckLintStatus(pkg) {
|
|
482
|
+
return exports.scanner.checkLintStatus(pkg);
|
|
483
|
+
}
|
|
484
|
+
async function funCheckSecurityAudit(pkg) {
|
|
485
|
+
return exports.scanner.checkSecurityAudit(pkg);
|
|
486
|
+
}
|