spec-up-t-healthcheck 1.0.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 +216 -0
- package/bin/cli.js +193 -0
- package/bin/demo-html.js +186 -0
- package/bin/simple-test.js +79 -0
- package/lib/checks/external-specs-urls.js +484 -0
- package/lib/checks/gitignore.js +350 -0
- package/lib/checks/package-json.js +518 -0
- package/lib/checks/spec-files.js +263 -0
- package/lib/checks/specsjson.js +361 -0
- package/lib/file-opener.js +127 -0
- package/lib/formatters.js +176 -0
- package/lib/health-check-orchestrator.js +413 -0
- package/lib/health-check-registry.js +396 -0
- package/lib/health-check-utils.js +234 -0
- package/lib/health-checker.js +145 -0
- package/lib/html-formatter.js +626 -0
- package/lib/index.js +123 -0
- package/lib/providers.js +184 -0
- package/lib/web.js +70 -0
- package/package.json +91 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Cross-platform file opener utility
|
|
3
|
+
*
|
|
4
|
+
* This module provides functionality to open files and URLs in the user's default
|
|
5
|
+
* application across different operating systems. It handles platform-specific
|
|
6
|
+
* commands and provides consistent error handling and feedback.
|
|
7
|
+
*
|
|
8
|
+
* @author spec-up-t-healthcheck
|
|
9
|
+
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { spawn } from 'child_process';
|
|
13
|
+
import { platform } from 'os';
|
|
14
|
+
import { existsSync } from 'fs';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Opens a file or URL in the default application.
|
|
18
|
+
*
|
|
19
|
+
* This function automatically detects the operating system and uses the appropriate
|
|
20
|
+
* command to open files or URLs. It provides cross-platform compatibility for
|
|
21
|
+
* opening HTML files in the default browser.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} target - The file path or URL to open
|
|
24
|
+
* @returns {Promise<boolean>} Promise that resolves to true if successful, false otherwise
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```javascript
|
|
28
|
+
* // Open an HTML file
|
|
29
|
+
* const success = await openFile('/path/to/report.html');
|
|
30
|
+
* if (success) {
|
|
31
|
+
* console.log('Report opened in browser');
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* // Open a URL
|
|
35
|
+
* await openFile('https://example.com');
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export async function openFile(target) {
|
|
39
|
+
return new Promise((resolve) => {
|
|
40
|
+
// Validate file exists if it's a local path
|
|
41
|
+
if (!target.startsWith('http') && !existsSync(target)) {
|
|
42
|
+
console.error(`File does not exist: ${target}`);
|
|
43
|
+
resolve(false);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const platformType = platform();
|
|
48
|
+
const commands = {
|
|
49
|
+
'darwin': ['open', target],
|
|
50
|
+
'win32': ['cmd', '/c', 'start', '', target],
|
|
51
|
+
'default': ['xdg-open', target]
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const [command, ...args] = commands[platformType] || commands.default;
|
|
55
|
+
|
|
56
|
+
const child = spawn(command, args, {
|
|
57
|
+
detached: true,
|
|
58
|
+
stdio: 'ignore'
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Simple error handling - resolve false on error, true on success
|
|
62
|
+
child.on('error', () => resolve(false));
|
|
63
|
+
child.on('spawn', () => {
|
|
64
|
+
child.unref();
|
|
65
|
+
resolve(true);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Opens an HTML file in the default browser.
|
|
72
|
+
*
|
|
73
|
+
* This is a convenience wrapper around openFile specifically for HTML files.
|
|
74
|
+
* It provides additional validation and more specific error messages for HTML content.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} htmlFilePath - Path to the HTML file to open
|
|
77
|
+
* @returns {Promise<boolean>} Promise that resolves to true if successful, false otherwise
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```javascript
|
|
81
|
+
* const reportPath = '/tmp/health-report.html';
|
|
82
|
+
* const opened = await openHtmlFile(reportPath);
|
|
83
|
+
* if (!opened) {
|
|
84
|
+
* console.error('Failed to open HTML report');
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export async function openHtmlFile(htmlFilePath) {
|
|
89
|
+
if (!htmlFilePath.toLowerCase().endsWith('.html') && !htmlFilePath.toLowerCase().endsWith('.htm')) {
|
|
90
|
+
console.warn('Warning: File does not appear to be an HTML file');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return await openFile(htmlFilePath);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Gets the platform-specific command for opening files.
|
|
98
|
+
*
|
|
99
|
+
* This utility function returns the command name that would be used to open files
|
|
100
|
+
* on the current platform. This is useful for debugging or displaying information to users.
|
|
101
|
+
* NOTE: This function only returns the command name as a string - it does NOT open files.
|
|
102
|
+
* To actually open files, use openFile() or openHtmlFile() instead.
|
|
103
|
+
*
|
|
104
|
+
* @returns {string} The platform-specific open command name
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```javascript
|
|
108
|
+
* const commandName = getOpenCommand();
|
|
109
|
+
* console.log(`Using command: ${commandName}`); // e.g., "open" on macOS
|
|
110
|
+
*
|
|
111
|
+
* // To actually open a file, use openFile() or openHtmlFile():
|
|
112
|
+
* const success = await openFile('report.html');
|
|
113
|
+
* const success2 = await openHtmlFile('report.html');
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export function getOpenCommand() {
|
|
117
|
+
const platformType = platform();
|
|
118
|
+
|
|
119
|
+
switch (platformType) {
|
|
120
|
+
case 'darwin':
|
|
121
|
+
return 'open';
|
|
122
|
+
case 'win32':
|
|
123
|
+
return 'start';
|
|
124
|
+
default:
|
|
125
|
+
return 'xdg-open';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Output formatters for health check results
|
|
3
|
+
*
|
|
4
|
+
* This module provides various formatting options for health check results,
|
|
5
|
+
* including human-readable text output with icons, structured JSON output,
|
|
6
|
+
* and interactive HTML reports with Bootstrap styling.
|
|
7
|
+
* The formatters support customization options and maintain consistent styling.
|
|
8
|
+
*
|
|
9
|
+
* @author spec-up-t-healthcheck
|
|
10
|
+
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { generateHtmlReport } from './html-formatter.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Formats health check results as human-readable text with emojis and structured layout.
|
|
17
|
+
*
|
|
18
|
+
* This formatter creates a comprehensive text report that's suitable for console output
|
|
19
|
+
* or text files. It includes a summary section, overall status, and detailed results
|
|
20
|
+
* for each individual check. The output uses Unicode emojis for visual clarity.
|
|
21
|
+
*
|
|
22
|
+
* @param {import('./health-checker.js').HealthCheckReport} healthCheckOutput - The complete health check report
|
|
23
|
+
* @param {boolean} [useColors=false] - Whether to include ANSI color codes (reserved for future use)
|
|
24
|
+
* @returns {string} Formatted text report ready for display or logging
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```javascript
|
|
28
|
+
* const report = await runHealthChecks(provider);
|
|
29
|
+
* const textOutput = formatResultsAsText(report);
|
|
30
|
+
* console.log(textOutput);
|
|
31
|
+
*
|
|
32
|
+
* // Example output:
|
|
33
|
+
* // 📋 Spec-up-t Health Check Report
|
|
34
|
+
* // Generated: 9/18/2025, 10:30:00 AM
|
|
35
|
+
* //
|
|
36
|
+
* // Repository: /path/to/spec
|
|
37
|
+
* //
|
|
38
|
+
* // 📊 Summary
|
|
39
|
+
* // Total checks: 2
|
|
40
|
+
* // ✓ Passed: 2
|
|
41
|
+
* // ✗ Failed: 0
|
|
42
|
+
* // Score: 100%
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function formatResultsAsText(healthCheckOutput, useColors = false) {
|
|
46
|
+
const { results, summary, timestamp, provider } = healthCheckOutput;
|
|
47
|
+
|
|
48
|
+
let output = [];
|
|
49
|
+
|
|
50
|
+
output.push('📋 Spec-up-t Health Check Report');
|
|
51
|
+
output.push(`Generated: ${new Date(timestamp).toLocaleString()}`);
|
|
52
|
+
output.push('');
|
|
53
|
+
|
|
54
|
+
if (provider.repoPath) {
|
|
55
|
+
output.push(`Repository: ${provider.repoPath}`);
|
|
56
|
+
}
|
|
57
|
+
output.push('');
|
|
58
|
+
|
|
59
|
+
output.push('📊 Summary');
|
|
60
|
+
output.push(`Total checks: ${summary.total}`);
|
|
61
|
+
output.push(`✓ Passed: ${summary.passed}`);
|
|
62
|
+
output.push(`✗ Failed: ${summary.failed}`);
|
|
63
|
+
if (summary.warnings > 0) output.push(`⚠ Warnings: ${summary.warnings}`);
|
|
64
|
+
if (summary.skipped > 0) output.push(`○ Skipped: ${summary.skipped}`);
|
|
65
|
+
output.push(`Score: ${Math.round(summary.score)}%`);
|
|
66
|
+
output.push('');
|
|
67
|
+
|
|
68
|
+
if (summary.hasErrors) {
|
|
69
|
+
output.push('❌ Overall Status: FAILED');
|
|
70
|
+
} else if (summary.hasWarnings) {
|
|
71
|
+
output.push('⚠️ Overall Status: PASSED WITH WARNINGS');
|
|
72
|
+
} else {
|
|
73
|
+
output.push('✅ Overall Status: PASSED');
|
|
74
|
+
}
|
|
75
|
+
output.push('');
|
|
76
|
+
|
|
77
|
+
output.push('📝 Detailed Results');
|
|
78
|
+
output.push('');
|
|
79
|
+
|
|
80
|
+
results.forEach((result, index) => {
|
|
81
|
+
const statusIcon = {
|
|
82
|
+
pass: '✓',
|
|
83
|
+
fail: '✗',
|
|
84
|
+
warn: '⚠',
|
|
85
|
+
skip: '○'
|
|
86
|
+
}[result.status];
|
|
87
|
+
|
|
88
|
+
output.push(`${index + 1}. ${statusIcon} ${result.check}`);
|
|
89
|
+
output.push(` ${result.message}`);
|
|
90
|
+
|
|
91
|
+
if (result.details && Object.keys(result.details).length > 0) {
|
|
92
|
+
if (result.details.missingFields) {
|
|
93
|
+
output.push(` Missing fields: ${result.details.missingFields.join(', ')}`);
|
|
94
|
+
}
|
|
95
|
+
if (result.details.count) {
|
|
96
|
+
output.push(` Files found: ${result.details.count}`);
|
|
97
|
+
}
|
|
98
|
+
if (result.details.packageData) {
|
|
99
|
+
output.push(` Package: ${result.details.packageData.name}@${result.details.packageData.version}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
output.push('');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
return output.join('\n');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Formats health check results as structured JSON with optional pretty-printing.
|
|
111
|
+
*
|
|
112
|
+
* This formatter converts the health check report to JSON format, making it suitable
|
|
113
|
+
* for programmatic consumption, API responses, or storage. The output maintains the
|
|
114
|
+
* complete structure of the original report with configurable indentation.
|
|
115
|
+
*
|
|
116
|
+
* @param {import('./health-checker.js').HealthCheckReport} healthCheckOutput - The complete health check report
|
|
117
|
+
* @param {number} [indent=2] - Number of spaces for JSON indentation (0 for compact output)
|
|
118
|
+
* @returns {string} JSON-formatted string representation of the health check report
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```javascript
|
|
122
|
+
* const report = await runHealthChecks(provider);
|
|
123
|
+
*
|
|
124
|
+
* // Pretty-printed JSON (default)
|
|
125
|
+
* const prettyJson = formatResultsAsJson(report);
|
|
126
|
+
*
|
|
127
|
+
* // Compact JSON
|
|
128
|
+
* const compactJson = formatResultsAsJson(report, 0);
|
|
129
|
+
*
|
|
130
|
+
* // Custom indentation
|
|
131
|
+
* const customJson = formatResultsAsJson(report, 4);
|
|
132
|
+
*
|
|
133
|
+
* // Parse back to object
|
|
134
|
+
* const parsedReport = JSON.parse(prettyJson);
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export function formatResultsAsJson(healthCheckOutput, indent = 2) {
|
|
138
|
+
return JSON.stringify(healthCheckOutput, null, indent);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Formats health check results as an interactive Bootstrap-styled HTML report.
|
|
143
|
+
*
|
|
144
|
+
* This formatter creates a comprehensive HTML document with responsive design,
|
|
145
|
+
* interactive filtering capabilities, and visual status indicators. The report
|
|
146
|
+
* follows modern web design patterns and provides an excellent user experience
|
|
147
|
+
* for reviewing health check results in a browser.
|
|
148
|
+
*
|
|
149
|
+
* @param {import('./health-checker.js').HealthCheckReport} healthCheckOutput - The complete health check report
|
|
150
|
+
* @param {Object} [options={}] - Configuration options for HTML generation
|
|
151
|
+
* @param {string} [options.title='Spec-Up-T Health Check Report'] - Custom title for the report
|
|
152
|
+
* @param {boolean} [options.showPassingByDefault=true] - Whether to show passing checks by default
|
|
153
|
+
* @param {string} [options.repositoryUrl] - URL to the repository being checked
|
|
154
|
+
* @returns {string} Complete HTML document ready for saving or displaying
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```javascript
|
|
158
|
+
* const report = await runHealthChecks(provider);
|
|
159
|
+
*
|
|
160
|
+
* // Basic HTML report
|
|
161
|
+
* const htmlReport = formatResultsAsHtml(report);
|
|
162
|
+
*
|
|
163
|
+
* // Customized HTML report
|
|
164
|
+
* const customHtml = formatResultsAsHtml(report, {
|
|
165
|
+
* title: 'My Project Health Check',
|
|
166
|
+
* repositoryUrl: 'https://github.com/user/repo',
|
|
167
|
+
* showPassingByDefault: false
|
|
168
|
+
* });
|
|
169
|
+
*
|
|
170
|
+
* // Save to file
|
|
171
|
+
* fs.writeFileSync('health-report.html', htmlReport);
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
export function formatResultsAsHtml(healthCheckOutput, options = {}) {
|
|
175
|
+
return generateHtmlReport(healthCheckOutput, options);
|
|
176
|
+
}
|