spec-up-t-healthcheck 1.0.0 → 1.1.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 +5 -0
- package/lib/checks/console-messages.js +211 -0
- package/lib/checks/external-specs-urls.js +93 -16
- package/lib/checks/gitignore.js +1 -1
- package/lib/checks/link-checker.js +361 -0
- package/lib/checks/package-json.js +1 -1
- package/lib/checks/spec-directory-and-files.js +356 -0
- package/lib/checks/specsjson.js +261 -5
- package/lib/formatters/result-details-formatter.js +505 -0
- package/lib/health-check-registry.js +57 -3
- package/lib/health-checker.js +13 -3
- package/lib/html-formatter.js +139 -168
- package/lib/index.js +1 -1
- package/lib/providers-browser.js +73 -0
- package/lib/providers.js +24 -0
- package/lib/web.js +10 -6
- package/package.json +5 -17
package/lib/html-formatter.js
CHANGED
|
@@ -7,9 +7,23 @@
|
|
|
7
7
|
* responsive design elements.
|
|
8
8
|
*
|
|
9
9
|
* @author spec-up-t-healthcheck
|
|
10
|
-
|
|
11
10
|
*/
|
|
12
11
|
|
|
12
|
+
// Import shared formatting functions
|
|
13
|
+
import {
|
|
14
|
+
formatResultDetails,
|
|
15
|
+
getStatusDisplay,
|
|
16
|
+
getRowClass,
|
|
17
|
+
escapeHtml,
|
|
18
|
+
linkifyUrls
|
|
19
|
+
} from './formatters/result-details-formatter.js';
|
|
20
|
+
|
|
21
|
+
// Import console message formatting functions
|
|
22
|
+
import {
|
|
23
|
+
formatConsoleMessageList,
|
|
24
|
+
formatConsoleMessagesTable
|
|
25
|
+
} from './formatters/result-details-formatter.js';
|
|
26
|
+
|
|
13
27
|
/**
|
|
14
28
|
* Generates a complete HTML report from health check results.
|
|
15
29
|
*
|
|
@@ -147,7 +161,7 @@ export function generateHtmlReport(healthCheckOutput, options = {}) {
|
|
|
147
161
|
}
|
|
148
162
|
.table td {
|
|
149
163
|
padding: 0.75rem;
|
|
150
|
-
vertical-align:
|
|
164
|
+
vertical-align: top;
|
|
151
165
|
}
|
|
152
166
|
.table-striped tbody tr:nth-of-type(odd) {
|
|
153
167
|
background-color: rgba(0, 0, 0, 0.02);
|
|
@@ -181,17 +195,22 @@ export function generateHtmlReport(healthCheckOutput, options = {}) {
|
|
|
181
195
|
.text-warning {
|
|
182
196
|
color: #fd7e14 !important;
|
|
183
197
|
}
|
|
198
|
+
.text-info {
|
|
199
|
+
color: #17a2b8 !important;
|
|
200
|
+
}
|
|
184
201
|
.text-muted {
|
|
185
202
|
color: #6c757d !important;
|
|
186
203
|
}
|
|
187
204
|
.detail-errors ul,
|
|
188
205
|
.detail-warnings ul,
|
|
206
|
+
.detail-info ul,
|
|
189
207
|
.detail-success ul {
|
|
190
208
|
padding-left: 1.25rem;
|
|
191
209
|
margin-top: 0.5rem;
|
|
192
210
|
}
|
|
193
211
|
.detail-errors li,
|
|
194
212
|
.detail-warnings li,
|
|
213
|
+
.detail-info li,
|
|
195
214
|
.detail-success li {
|
|
196
215
|
margin-bottom: 0.25rem;
|
|
197
216
|
}
|
|
@@ -295,7 +314,7 @@ function generateSummarySection(summary, showPassingByDefault) {
|
|
|
295
314
|
Health Check Summary
|
|
296
315
|
</h5>
|
|
297
316
|
<div class="filter-toggle form-check form-switch">
|
|
298
|
-
<input class="form-check-input" type="checkbox" id="togglePassingChecks"
|
|
317
|
+
<input class="form-check-input" type="checkbox" id="togglePassingChecks">
|
|
299
318
|
<label class="form-check-label" for="togglePassingChecks">
|
|
300
319
|
Show passing checks
|
|
301
320
|
</label>
|
|
@@ -362,6 +381,12 @@ function generateResultsSection(results) {
|
|
|
362
381
|
}
|
|
363
382
|
|
|
364
383
|
const resultsHtml = results.map((result, index) => {
|
|
384
|
+
// Special handling for console-messages check: split into two rows
|
|
385
|
+
if (result.check === 'console-messages' && result.details && result.details.analysis) {
|
|
386
|
+
return generateConsoleMessagesRows(result);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Regular handling for other checks
|
|
365
390
|
const { statusClass, statusIcon, statusText } = getStatusDisplay(result);
|
|
366
391
|
const rowClass = getRowClass(result);
|
|
367
392
|
|
|
@@ -407,6 +432,117 @@ function generateResultsSection(results) {
|
|
|
407
432
|
</div>`;
|
|
408
433
|
}
|
|
409
434
|
|
|
435
|
+
/**
|
|
436
|
+
* Generates separate rows for console-messages check:
|
|
437
|
+
* 1. Fail row with errors (if any)
|
|
438
|
+
* 2. Warning row with warnings (if any)
|
|
439
|
+
* 3. Pass row with successful operations
|
|
440
|
+
*
|
|
441
|
+
* @param {import('./health-checker.js').HealthCheckResult} result - Console messages result
|
|
442
|
+
* @returns {string} HTML string with table rows
|
|
443
|
+
*/
|
|
444
|
+
function generateConsoleMessagesRows(result) {
|
|
445
|
+
const { analysis, errors, warnings, allMessages } = result.details;
|
|
446
|
+
|
|
447
|
+
let html = '';
|
|
448
|
+
|
|
449
|
+
// Row 1: Errors (if any)
|
|
450
|
+
if (errors && errors.length > 0) {
|
|
451
|
+
const errorDetailsHtml = formatConsoleMessageList('Errors', errors, 'danger');
|
|
452
|
+
const errorNote = result.details.errorsNote ? `<div class="mt-1"><small class="text-muted">${escapeHtml(result.details.errorsNote)}</small></div>` : '';
|
|
453
|
+
|
|
454
|
+
html += `<tr data-status="fail" class="check-row table-danger">
|
|
455
|
+
<td class="text-danger status-badge">
|
|
456
|
+
<i class="bi bi-x-circle-fill status-icon"></i>
|
|
457
|
+
<span>Fail</span>
|
|
458
|
+
</td>
|
|
459
|
+
<td>Terms & Definitions (errors)</td>
|
|
460
|
+
<td>
|
|
461
|
+
Found ${errors.length} error(s) in console output
|
|
462
|
+
${errorDetailsHtml}
|
|
463
|
+
${errorNote}
|
|
464
|
+
</td>
|
|
465
|
+
</tr>`;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Row 2: Warnings (if any)
|
|
469
|
+
if (warnings && warnings.length > 0) {
|
|
470
|
+
const warningDetailsHtml = formatConsoleMessageList('Warnings', warnings, 'warning');
|
|
471
|
+
const warningNote = result.details.warningsNote ? `<div class="mt-1"><small class="text-muted">${escapeHtml(result.details.warningsNote)}</small></div>` : '';
|
|
472
|
+
|
|
473
|
+
html += `<tr data-status="warn" class="check-row table-warning">
|
|
474
|
+
<td class="text-warning status-badge">
|
|
475
|
+
<i class="bi bi-exclamation-triangle-fill status-icon"></i>
|
|
476
|
+
<span>Warning</span>
|
|
477
|
+
</td>
|
|
478
|
+
<td>Terms & Definitions (warnings)</td>
|
|
479
|
+
<td>
|
|
480
|
+
Found ${warnings.length} warning(s) in console output
|
|
481
|
+
${warningDetailsHtml}
|
|
482
|
+
${warningNote}
|
|
483
|
+
</td>
|
|
484
|
+
</tr>`;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Row 3: Successful operations (pass)
|
|
488
|
+
if (allMessages && allMessages.length > 0) {
|
|
489
|
+
// Filter out error and warning messages AND exclude separator, process, and info types
|
|
490
|
+
const valuableMessages = allMessages.filter(m =>
|
|
491
|
+
m.type !== 'error' &&
|
|
492
|
+
m.type !== 'warn' &&
|
|
493
|
+
m.type !== 'separator' &&
|
|
494
|
+
m.type !== 'process' &&
|
|
495
|
+
m.type !== 'info'
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
if (valuableMessages.length === 0) {
|
|
499
|
+
// If no valuable messages after filtering, don't show the Pass row
|
|
500
|
+
return html;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const valuableCount = valuableMessages.length;
|
|
504
|
+
|
|
505
|
+
// Count by type for display (only valuable types)
|
|
506
|
+
const typeCounts = {};
|
|
507
|
+
valuableMessages.forEach(m => {
|
|
508
|
+
typeCounts[m.type] = (typeCounts[m.type] || 0) + 1;
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
const typesList = Object.entries(typeCounts)
|
|
512
|
+
.map(([type, count]) => `${count} ${type}`)
|
|
513
|
+
.join(', ');
|
|
514
|
+
|
|
515
|
+
// Create modified details object with only valuable messages
|
|
516
|
+
const filteredDetails = {
|
|
517
|
+
...result.details,
|
|
518
|
+
allMessages: valuableMessages,
|
|
519
|
+
analysis: {
|
|
520
|
+
...result.details.analysis,
|
|
521
|
+
totalMessages: valuableMessages.length,
|
|
522
|
+
errorCount: 0, // No errors in valuable messages (they're filtered out)
|
|
523
|
+
warningCount: 0, // No warnings in valuable messages (they're filtered out)
|
|
524
|
+
successCount: valuableMessages.filter(m => m.type === 'success').length
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
const allMessagesHtml = formatConsoleMessagesTable(filteredDetails);
|
|
529
|
+
|
|
530
|
+
html += `<tr data-status="pass" class="check-row table-success">
|
|
531
|
+
<td class="text-success status-badge">
|
|
532
|
+
<i class="bi bi-check-circle-fill status-icon"></i>
|
|
533
|
+
<span>Pass</span>
|
|
534
|
+
</td>
|
|
535
|
+
<td>Terms & Definitions (operations)</td>
|
|
536
|
+
<td>
|
|
537
|
+
${valuableCount} successful operations (${typesList})
|
|
538
|
+
${allMessagesHtml}
|
|
539
|
+
</td>
|
|
540
|
+
</tr>`;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return html;
|
|
544
|
+
}
|
|
545
|
+
|
|
410
546
|
/**
|
|
411
547
|
* Generates the JavaScript section for interactive functionality.
|
|
412
548
|
*
|
|
@@ -458,169 +594,4 @@ function generateScriptsSection() {
|
|
|
458
594
|
// Initialize the filter state
|
|
459
595
|
document.getElementById('togglePassingChecks').dispatchEvent(new Event('change'));
|
|
460
596
|
</script>`;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* Gets the appropriate display properties for a health check result status.
|
|
465
|
-
*
|
|
466
|
-
* @param {import('./health-checker.js').HealthCheckResult} result - The health check result
|
|
467
|
-
* @returns {Object} Object containing statusClass, statusIcon, and statusText
|
|
468
|
-
*/
|
|
469
|
-
function getStatusDisplay(result) {
|
|
470
|
-
switch (result.status) {
|
|
471
|
-
case 'pass':
|
|
472
|
-
return {
|
|
473
|
-
statusClass: 'text-success',
|
|
474
|
-
statusIcon: 'bi-check-circle-fill',
|
|
475
|
-
statusText: 'Pass'
|
|
476
|
-
};
|
|
477
|
-
case 'fail':
|
|
478
|
-
return {
|
|
479
|
-
statusClass: 'text-danger',
|
|
480
|
-
statusIcon: 'bi-x-circle-fill',
|
|
481
|
-
statusText: 'Fail'
|
|
482
|
-
};
|
|
483
|
-
case 'warn':
|
|
484
|
-
return {
|
|
485
|
-
statusClass: 'text-warning',
|
|
486
|
-
statusIcon: 'bi-exclamation-triangle-fill',
|
|
487
|
-
statusText: 'Warning'
|
|
488
|
-
};
|
|
489
|
-
case 'skip':
|
|
490
|
-
return {
|
|
491
|
-
statusClass: 'text-muted',
|
|
492
|
-
statusIcon: 'bi-dash-circle',
|
|
493
|
-
statusText: 'Skipped'
|
|
494
|
-
};
|
|
495
|
-
default:
|
|
496
|
-
return {
|
|
497
|
-
statusClass: 'text-secondary',
|
|
498
|
-
statusIcon: 'bi-question-circle',
|
|
499
|
-
statusText: 'Unknown'
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* Gets the appropriate CSS class for a table row based on the result status.
|
|
506
|
-
*
|
|
507
|
-
* @param {import('./health-checker.js').HealthCheckResult} result - The health check result
|
|
508
|
-
* @returns {string} CSS class name
|
|
509
|
-
*/
|
|
510
|
-
function getRowClass(result) {
|
|
511
|
-
switch (result.status) {
|
|
512
|
-
case 'fail':
|
|
513
|
-
return 'table-danger';
|
|
514
|
-
case 'warn':
|
|
515
|
-
return 'table-warning';
|
|
516
|
-
case 'pass':
|
|
517
|
-
return 'table-success';
|
|
518
|
-
default:
|
|
519
|
-
return '';
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
/**
|
|
524
|
-
* Formats result details into HTML.
|
|
525
|
-
*
|
|
526
|
-
* @param {Object} details - The details object from a health check result
|
|
527
|
-
* @returns {string} Formatted HTML string
|
|
528
|
-
*/
|
|
529
|
-
function formatResultDetails(details) {
|
|
530
|
-
let html = '';
|
|
531
|
-
|
|
532
|
-
// Display errors array with clickable URLs
|
|
533
|
-
if (details.errors && details.errors.length > 0) {
|
|
534
|
-
html += `<div class="mt-2 detail-errors"><strong class="text-danger">Errors:</strong><ul class="mb-0 mt-1">`;
|
|
535
|
-
details.errors.forEach(error => {
|
|
536
|
-
html += `<li class="text-danger">${linkifyUrls(error)}</li>`;
|
|
537
|
-
});
|
|
538
|
-
html += `</ul></div>`;
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
// Display warnings array with clickable URLs
|
|
542
|
-
if (details.warnings && details.warnings.length > 0) {
|
|
543
|
-
html += `<div class="mt-2 detail-warnings"><strong class="text-warning">Warnings:</strong><ul class="mb-0 mt-1">`;
|
|
544
|
-
details.warnings.forEach(warning => {
|
|
545
|
-
html += `<li class="text-warning">${linkifyUrls(warning)}</li>`;
|
|
546
|
-
});
|
|
547
|
-
html += `</ul></div>`;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// Display success messages array with clickable URLs
|
|
551
|
-
// Add detail-success class so these can be hidden when "Show passing checks" is disabled
|
|
552
|
-
if (details.success && details.success.length > 0) {
|
|
553
|
-
html += `<div class="mt-2 detail-success"><strong class="text-success">Success:</strong><ul class="mb-0 mt-1">`;
|
|
554
|
-
details.success.forEach(success => {
|
|
555
|
-
html += `<li class="text-success">${linkifyUrls(success)}</li>`;
|
|
556
|
-
});
|
|
557
|
-
html += `</ul></div>`;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
// Display missing fields (existing functionality)
|
|
561
|
-
if (details.missingFields && details.missingFields.length > 0) {
|
|
562
|
-
html += `<br><small class="text-muted">Missing fields: ${details.missingFields.map(escapeHtml).join(', ')}</small>`;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// Display count (existing functionality)
|
|
566
|
-
if (details.count !== undefined) {
|
|
567
|
-
html += `<br><small class="text-muted">Files found: ${details.count}</small>`;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
// Display package data (existing functionality)
|
|
571
|
-
if (details.packageData) {
|
|
572
|
-
html += `<br><small class="text-muted">Package: ${escapeHtml(details.packageData.name)}@${escapeHtml(details.packageData.version)}</small>`;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
return html;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
/**
|
|
579
|
-
* Escapes HTML special characters to prevent XSS attacks.
|
|
580
|
-
*
|
|
581
|
-
* @param {string} text - Text to escape
|
|
582
|
-
* @returns {string} HTML-escaped text
|
|
583
|
-
*/
|
|
584
|
-
function escapeHtml(text) {
|
|
585
|
-
if (typeof text !== 'string') {
|
|
586
|
-
return String(text);
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
const map = {
|
|
590
|
-
'&': '&',
|
|
591
|
-
'<': '<',
|
|
592
|
-
'>': '>',
|
|
593
|
-
'"': '"',
|
|
594
|
-
"'": '''
|
|
595
|
-
};
|
|
596
|
-
|
|
597
|
-
return text.replace(/[&<>"']/g, (m) => map[m]);
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* Converts URLs in text to clickable links that open in a new tab.
|
|
602
|
-
* The text is first escaped for HTML safety, then URLs are converted to links.
|
|
603
|
-
*
|
|
604
|
-
* @param {string} text - Text potentially containing URLs
|
|
605
|
-
* @returns {string} HTML string with clickable links
|
|
606
|
-
*/
|
|
607
|
-
function linkifyUrls(text) {
|
|
608
|
-
if (typeof text !== 'string') {
|
|
609
|
-
return escapeHtml(String(text));
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// First escape the text for HTML safety
|
|
613
|
-
const escaped = escapeHtml(text);
|
|
614
|
-
|
|
615
|
-
// URL regex pattern that matches http://, https://, and www. URLs
|
|
616
|
-
const urlPattern = /(https?:\/\/[^\s<>"]+|www\.[^\s<>"]+)/g;
|
|
617
|
-
|
|
618
|
-
// Replace URLs with clickable links
|
|
619
|
-
return escaped.replace(urlPattern, (url) => {
|
|
620
|
-
// Ensure the URL has a protocol for the href attribute
|
|
621
|
-
const href = url.startsWith('http') ? url : `https://${url}`;
|
|
622
|
-
|
|
623
|
-
// Create an anchor tag that opens in a new tab with security attributes
|
|
624
|
-
return `<a href="${href}" target="_blank" rel="noopener noreferrer" class="text-decoration-underline">${url}</a>`;
|
|
625
|
-
});
|
|
626
597
|
}
|
package/lib/index.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
export { createProvider, createLocalProvider } from './providers.js';
|
|
15
15
|
|
|
16
16
|
// Re-export health checking functionality
|
|
17
|
-
export { runHealthChecks, createHealthCheckResult, checkPackageJson, checkSpecFiles, checkSpecsJson, checkExternalSpecsUrls, checkGitignore } from './health-checker.js';
|
|
17
|
+
export { runHealthChecks, createHealthCheckResult, checkPackageJson, checkSpecFiles, checkSpecsJson, checkExternalSpecsUrls, checkGitignore, checkSpecDirectoryAndFiles, checkConsoleMessages } from './health-checker.js';
|
|
18
18
|
|
|
19
19
|
// Re-export formatting functionality
|
|
20
20
|
export { formatResultsAsText, formatResultsAsJson, formatResultsAsHtml } from './formatters.js';
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Browser-compatible providers module
|
|
3
|
+
*
|
|
4
|
+
* This is a browser-safe version of providers.js that doesn't import Node.js modules.
|
|
5
|
+
* It only exports the createProvider function interface without the Node.js-specific
|
|
6
|
+
* LocalFileProvider.
|
|
7
|
+
*
|
|
8
|
+
* In browser environments, providers must be created by the consuming application
|
|
9
|
+
* (e.g., GitHubUi creates a GitHub API provider).
|
|
10
|
+
*
|
|
11
|
+
* @author spec-up-t-healthcheck
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} FileEntry
|
|
16
|
+
* @property {string} name - The name of the file or directory
|
|
17
|
+
* @property {string} path - The relative path from the repository root
|
|
18
|
+
* @property {boolean} isDirectory - Whether this entry is a directory
|
|
19
|
+
* @property {boolean} isFile - Whether this entry is a file
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {Object} Provider
|
|
24
|
+
* @property {string} type - The type of provider ('local', 'remote', etc.)
|
|
25
|
+
* @property {string} repoPath - The base path or URL for the repository
|
|
26
|
+
* @property {function(string): Promise<string>} readFile - Read a file and return its content
|
|
27
|
+
* @property {function(string): Promise<boolean>} fileExists - Check if a file exists
|
|
28
|
+
* @property {function(string): Promise<FileEntry[]>} listFiles - List files in a directory
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates a provider based on the given configuration.
|
|
33
|
+
*
|
|
34
|
+
* In browser environments, only custom providers are supported.
|
|
35
|
+
* You must pass a pre-configured provider object.
|
|
36
|
+
*
|
|
37
|
+
* @param {Object|string} config - Provider configuration or custom provider
|
|
38
|
+
* @returns {Provider} The configured provider
|
|
39
|
+
* @throws {Error} If trying to create a local file provider in browser
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```javascript
|
|
43
|
+
* // Browser: Pass a custom provider (e.g., GitHub API provider)
|
|
44
|
+
* const provider = createProvider({
|
|
45
|
+
* type: 'github',
|
|
46
|
+
* repoPath: 'owner/repo/branch',
|
|
47
|
+
* readFile: async (path) => { ... },
|
|
48
|
+
* fileExists: async (path) => { ... },
|
|
49
|
+
* listFiles: async (dir) => { ... }
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function createProvider(config) {
|
|
54
|
+
// If config is already a provider object with required methods, return it
|
|
55
|
+
if (typeof config === 'object' &&
|
|
56
|
+
config.readFile &&
|
|
57
|
+
config.fileExists) {
|
|
58
|
+
return config;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// If config is a string (file path), this is not supported in browser
|
|
62
|
+
if (typeof config === 'string') {
|
|
63
|
+
throw new Error(
|
|
64
|
+
'Local file system providers are not available in browser environments. ' +
|
|
65
|
+
'Please provide a custom provider object with readFile, fileExists, and listFiles methods.'
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
throw new Error(
|
|
70
|
+
'Invalid provider configuration. In browser environments, you must provide a ' +
|
|
71
|
+
'custom provider object with readFile, fileExists, and listFiles methods.'
|
|
72
|
+
);
|
|
73
|
+
}
|
package/lib/providers.js
CHANGED
|
@@ -115,6 +115,30 @@ export function createLocalProvider(repoPath) {
|
|
|
115
115
|
}
|
|
116
116
|
},
|
|
117
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Checks whether a directory exists in the local filesystem.
|
|
120
|
+
*
|
|
121
|
+
* @param {string} dirPath - The relative path to the directory from the repository root
|
|
122
|
+
* @returns {Promise<boolean>} True if the directory exists, false otherwise
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```javascript
|
|
126
|
+
* const exists = await provider.directoryExists('spec');
|
|
127
|
+
* if (exists) {
|
|
128
|
+
* console.log('Spec directory found');
|
|
129
|
+
* }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
async directoryExists(dirPath) {
|
|
133
|
+
const fullPath = path.join(repoPath, dirPath);
|
|
134
|
+
try {
|
|
135
|
+
const stats = await fs.stat(fullPath);
|
|
136
|
+
return stats.isDirectory();
|
|
137
|
+
} catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
|
|
118
142
|
/**
|
|
119
143
|
* Lists all files and directories in the specified directory.
|
|
120
144
|
*
|
package/lib/web.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Browser-compatible entry point for spec-up-t-healthcheck
|
|
3
3
|
*
|
|
4
|
-
* This module provides a browser-safe API that excludes Node.js-specific modules
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* This module provides a browser-safe API that excludes Node.js-specific modules:
|
|
5
|
+
* - file-opener (depends on child_process)
|
|
6
|
+
* - link-checker (depends on linkinator with Node.js streams)
|
|
7
|
+
* - providers (uses providers-browser.js instead of providers.js)
|
|
8
|
+
*
|
|
9
|
+
* The auto-discovery system will automatically skip Node.js-only checks
|
|
10
|
+
* when running in a browser environment.
|
|
7
11
|
*
|
|
8
12
|
* @author spec-up-t-healthcheck
|
|
9
13
|
*/
|
|
10
14
|
|
|
11
|
-
// Re-export provider functionality (browser-compatible)
|
|
12
|
-
export { createProvider } from './providers.js';
|
|
15
|
+
// Re-export provider functionality (browser-compatible version without Node.js imports)
|
|
16
|
+
export { createProvider } from './providers-browser.js';
|
|
13
17
|
|
|
14
18
|
// Re-export health checking functionality (browser-compatible)
|
|
15
19
|
export {
|
|
@@ -28,7 +32,7 @@ export {
|
|
|
28
32
|
} from './formatters.js';
|
|
29
33
|
|
|
30
34
|
// Import functions for internal use
|
|
31
|
-
import { createProvider } from './providers.js';
|
|
35
|
+
import { createProvider } from './providers-browser.js';
|
|
32
36
|
import { runHealthChecks } from './health-checker.js';
|
|
33
37
|
|
|
34
38
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec-up-t-healthcheck",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Modular health check tool for spec-up-t repositories - works in Node.js, browsers, and CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./lib/index.js",
|
|
12
|
-
"./web": "./lib/web.js"
|
|
12
|
+
"./web": "./lib/web.js",
|
|
13
|
+
"./lib/formatters/result-details-formatter.js": "./lib/formatters/result-details-formatter.js"
|
|
13
14
|
},
|
|
14
15
|
"scripts": {
|
|
15
16
|
"test": "jest",
|
|
@@ -56,7 +57,8 @@
|
|
|
56
57
|
"axios": "^1.6.7",
|
|
57
58
|
"commander": "^12.0.0",
|
|
58
59
|
"chalk": "^5.3.0",
|
|
59
|
-
"ora": "^8.0.1"
|
|
60
|
+
"ora": "^8.0.1",
|
|
61
|
+
"linkinator": "^7.1.3"
|
|
60
62
|
},
|
|
61
63
|
"devDependencies": {
|
|
62
64
|
"eslint": "^8.57.0",
|
|
@@ -73,19 +75,5 @@
|
|
|
73
75
|
},
|
|
74
76
|
"publishConfig": {
|
|
75
77
|
"access": "public"
|
|
76
|
-
},
|
|
77
|
-
"overrides": {
|
|
78
|
-
"@jest/environment": "^29.7.0",
|
|
79
|
-
"@jest/environment-jsdom-abstract": "^29.7.0",
|
|
80
|
-
"@jest/fake-timers": "^29.7.0",
|
|
81
|
-
"@jest/schemas": "^29.7.0",
|
|
82
|
-
"@jest/types": "^29.7.0",
|
|
83
|
-
"jest-environment-jsdom": "^29.7.0",
|
|
84
|
-
"jest-message-util": "^29.7.0",
|
|
85
|
-
"jest-mock": "^29.7.0",
|
|
86
|
-
"jest-util": "^29.7.0",
|
|
87
|
-
"pretty-format": "^29.7.0",
|
|
88
|
-
"@jest/pattern": "^29.7.0",
|
|
89
|
-
"jest-regex-util": "^29.7.0"
|
|
90
78
|
}
|
|
91
79
|
}
|