spec-up-t 1.4.1 → 1.6.0-beta.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/assets/compiled/body.js +3 -2
- package/assets/compiled/head.css +5 -5
- package/assets/css/embedded-libraries/bootstrap.min.css +1 -1
- package/assets/css/header-navbar.css +4 -4
- package/assets/css/index.css +5 -4
- package/assets/css/refs.css +30 -0
- package/assets/css/terms-and-definitions.css +89 -1
- package/assets/js/github-issues.js +3 -3
- package/assets/js/insert-irefs.js +214 -0
- package/config/asset-map.json +2 -1
- package/examples/read-console-messages.js +102 -0
- package/gulpfile.js +42 -1
- package/index.js +49 -1
- package/package.json +2 -1
- package/src/create-docx.js +13 -6
- package/src/create-pdf.js +22 -18
- package/src/health-check.js +47 -629
- package/src/init.js +7 -3
- package/src/install-from-boilerplate/config-scripts-keys.js +1 -1
- package/src/markdown-it/README.md +2 -14
- package/src/markdown-it/index.js +1 -7
- package/src/parsers/template-tag-parser.js +42 -4
- package/src/pipeline/postprocessing/definition-list-postprocessor.js +4 -2
- package/src/pipeline/references/collect-external-references.js +101 -17
- package/src/pipeline/references/external-references-service.js +102 -21
- package/src/pipeline/references/fetch-terms-from-index.js +62 -1
- package/src/pipeline/references/process-xtrefs-data.js +67 -9
- package/src/pipeline/references/xtref-utils.js +22 -3
- package/src/pipeline/rendering/render-spec-document.js +0 -1
- package/src/run-healthcheck.js +177 -0
- package/src/utils/logger.js +129 -8
- package/src/utils/message-collector.js +144 -0
- package/src/utils/regex-patterns.js +3 -1
- package/templates/template.html +6 -6
- package/test/logger.test.js +290 -0
- package/test/message-collector.test.js +286 -0
- package/assets/css/insert-trefs.css +0 -1
- package/src/markdown-it/link-enhancement.js +0 -98
- package/src/utils/LOGGER.md +0 -81
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Check Integration Script for spec-up-t
|
|
3
|
+
*
|
|
4
|
+
* This script integrates the spec-up-t-healthcheck tool to validate consuming projects.
|
|
5
|
+
* It runs FROM spec-up-t (menu option 7) but checks the CONSUMING project (current directory).
|
|
6
|
+
*
|
|
7
|
+
* Usage (from consuming project):
|
|
8
|
+
* npm run healthCheck
|
|
9
|
+
*
|
|
10
|
+
* Or via spec-up-t menu:
|
|
11
|
+
* npm run menu -> [7] Run health check
|
|
12
|
+
*
|
|
13
|
+
* Options:
|
|
14
|
+
* --format text|json|html Output format (default: html)
|
|
15
|
+
* --output <file> Output file path
|
|
16
|
+
* --checks <checks> Comma-separated list of specific checks
|
|
17
|
+
*
|
|
18
|
+
* Examples:
|
|
19
|
+
* node run-healthcheck.js
|
|
20
|
+
* node run-healthcheck.js --format json
|
|
21
|
+
* node run-healthcheck.js --format html --output health-report.html
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const fs = require('fs').promises;
|
|
25
|
+
const path = require('path');
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Parse command line arguments
|
|
29
|
+
* Handles both direct node invocations and npm script invocations
|
|
30
|
+
*
|
|
31
|
+
* @returns {Object} Parsed arguments
|
|
32
|
+
*/
|
|
33
|
+
function parseArgs() {
|
|
34
|
+
const args = process.argv.slice(2);
|
|
35
|
+
const options = {
|
|
36
|
+
format: 'html', // Changed default to HTML for better user experience
|
|
37
|
+
output: null,
|
|
38
|
+
checks: null
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < args.length; i++) {
|
|
42
|
+
if (args[i] === '--format' && args[i + 1]) {
|
|
43
|
+
options.format = args[i + 1];
|
|
44
|
+
i++;
|
|
45
|
+
} else if (args[i] === '--output' && args[i + 1]) {
|
|
46
|
+
options.output = args[i + 1];
|
|
47
|
+
i++;
|
|
48
|
+
} else if (args[i] === '--checks' && args[i + 1]) {
|
|
49
|
+
options.checks = args[i + 1].split(',');
|
|
50
|
+
i++;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return options;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Main execution function
|
|
59
|
+
*
|
|
60
|
+
* Runs health checks on the CONSUMING PROJECT (current working directory).
|
|
61
|
+
* This script is part of spec-up-t but validates the project that uses spec-up-t.
|
|
62
|
+
*/
|
|
63
|
+
async function main() {
|
|
64
|
+
try {
|
|
65
|
+
console.log('🏥 Spec-Up-T Health Check\n');
|
|
66
|
+
console.log('📍 Checking consuming project in:', process.cwd());
|
|
67
|
+
console.log('');
|
|
68
|
+
|
|
69
|
+
// Parse command line arguments
|
|
70
|
+
const options = parseArgs();
|
|
71
|
+
|
|
72
|
+
// Import the health check tool
|
|
73
|
+
const {
|
|
74
|
+
createProvider,
|
|
75
|
+
runHealthChecks,
|
|
76
|
+
formatResultsAsText,
|
|
77
|
+
formatResultsAsJson,
|
|
78
|
+
formatResultsAsHtml
|
|
79
|
+
} = await import('spec-up-t-healthcheck');
|
|
80
|
+
|
|
81
|
+
// Create a provider for the CURRENT WORKING DIRECTORY (the consuming project)
|
|
82
|
+
const provider = createProvider(process.cwd());
|
|
83
|
+
|
|
84
|
+
// Run health checks on the consuming project
|
|
85
|
+
console.log('🔍 Running health checks on consuming project...');
|
|
86
|
+
const healthCheckOptions = {};
|
|
87
|
+
if (options.checks) {
|
|
88
|
+
healthCheckOptions.checks = options.checks;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const results = await runHealthChecks(provider, healthCheckOptions);
|
|
92
|
+
|
|
93
|
+
// Display summary
|
|
94
|
+
console.log('\n📊 Health Check Summary:');
|
|
95
|
+
console.log(` Total Checks: ${results.summary.total}`);
|
|
96
|
+
console.log(` ✅ Passed: ${results.summary.passed}`);
|
|
97
|
+
console.log(` ❌ Failed: ${results.summary.failed}`);
|
|
98
|
+
console.log(` ⚠️ Warnings: ${results.summary.warnings}`);
|
|
99
|
+
console.log(` ⏭️ Skipped: ${results.summary.skipped}`);
|
|
100
|
+
console.log(` 📈 Health Score: ${results.summary.score}%\n`);
|
|
101
|
+
|
|
102
|
+
// Format results based on requested format
|
|
103
|
+
let output;
|
|
104
|
+
let defaultFilename;
|
|
105
|
+
|
|
106
|
+
switch (options.format) {
|
|
107
|
+
case 'json':
|
|
108
|
+
output = formatResultsAsJson(results);
|
|
109
|
+
defaultFilename = 'health-report.json';
|
|
110
|
+
break;
|
|
111
|
+
|
|
112
|
+
case 'html':
|
|
113
|
+
output = formatResultsAsHtml(results, {
|
|
114
|
+
title: 'Spec-Up-T Project Health Check',
|
|
115
|
+
repositoryUrl: results.provider.repoPath ?
|
|
116
|
+
`file://${results.provider.repoPath}` : undefined
|
|
117
|
+
});
|
|
118
|
+
defaultFilename = 'health-report.html';
|
|
119
|
+
break;
|
|
120
|
+
|
|
121
|
+
case 'text':
|
|
122
|
+
default:
|
|
123
|
+
output = formatResultsAsText(results);
|
|
124
|
+
defaultFilename = 'health-report.txt';
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Determine output path
|
|
129
|
+
const outputPath = options.output || defaultFilename;
|
|
130
|
+
|
|
131
|
+
// Save to file
|
|
132
|
+
await fs.writeFile(outputPath, output);
|
|
133
|
+
console.log(`📄 Report saved to: ${outputPath}`);
|
|
134
|
+
|
|
135
|
+
// For HTML format, try to open in browser
|
|
136
|
+
if (options.format === 'html' && !options.output) {
|
|
137
|
+
try {
|
|
138
|
+
const { openHtmlFile } = require('./utils/file-opener');
|
|
139
|
+
await openHtmlFile(path.resolve(outputPath));
|
|
140
|
+
console.log('🌐 Opening report in browser...');
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.log('ℹ️ Tip: Open the report manually in your browser');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// For text format, also print to console
|
|
147
|
+
if (options.format === 'text') {
|
|
148
|
+
console.log('\n' + output);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Exit with appropriate code
|
|
152
|
+
if (results.summary.hasErrors) {
|
|
153
|
+
console.error('\n❌ Health check completed with errors');
|
|
154
|
+
console.error(' Please review the report for details');
|
|
155
|
+
process.exit(1);
|
|
156
|
+
} else if (results.summary.hasWarnings) {
|
|
157
|
+
console.warn('\n⚠️ Health check completed with warnings');
|
|
158
|
+
process.exit(0);
|
|
159
|
+
} else {
|
|
160
|
+
console.log('\n✅ Health check completed successfully');
|
|
161
|
+
console.log(' All checks passed!');
|
|
162
|
+
process.exit(0);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error('\n❌ Health check failed:', error.message);
|
|
167
|
+
console.error('\nDetails:', error.stack);
|
|
168
|
+
console.error('\nTroubleshooting:');
|
|
169
|
+
console.error(' - Ensure you are running this from a consuming project directory');
|
|
170
|
+
console.error(' - Check that spec-up-t-healthcheck is properly installed');
|
|
171
|
+
console.error(' - Verify the consuming project has a valid package.json');
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Run the script
|
|
177
|
+
main();
|
package/src/utils/logger.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
+
const messageCollector = require('./message-collector');
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Logger utility with color-coded console output
|
|
5
6
|
* Provides consistent logging across the spec-up-t application
|
|
7
|
+
*
|
|
8
|
+
* All messages are automatically collected when message collection is active,
|
|
9
|
+
* allowing healthchecks and other tools to consume the output in JSON format.
|
|
6
10
|
*/
|
|
7
11
|
class Logger {
|
|
8
12
|
/**
|
|
@@ -10,27 +14,128 @@ class Logger {
|
|
|
10
14
|
*/
|
|
11
15
|
static success(message, ...args) {
|
|
12
16
|
console.log(chalk.green('✅'), chalk.green(message), ...args);
|
|
17
|
+
messageCollector.addMessage('success', message, args);
|
|
18
|
+
|
|
19
|
+
console.log(); // Extra newline for readability
|
|
13
20
|
}
|
|
14
21
|
|
|
15
22
|
/**
|
|
16
23
|
* Error messages - red with X mark
|
|
24
|
+
*
|
|
25
|
+
* Enhanced error logging with optional context and actionable guidance.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} message - The main error message
|
|
28
|
+
* @param {...any} args - Additional arguments. Can include:
|
|
29
|
+
* - Regular values (strings, numbers, objects) for message formatting
|
|
30
|
+
* - An options object (if last arg is object with 'hint', 'context', or 'details' keys):
|
|
31
|
+
* - hint: Actionable suggestion for fixing the error
|
|
32
|
+
* - context: Additional context about where/why the error occurred
|
|
33
|
+
* - details: Technical details or error objects
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* Logger.error('File not found', {
|
|
37
|
+
* context: 'specs.json',
|
|
38
|
+
* hint: 'Create a specs.json file in your project root',
|
|
39
|
+
* details: error.message
|
|
40
|
+
* });
|
|
17
41
|
*/
|
|
18
42
|
static error(message, ...args) {
|
|
19
|
-
|
|
43
|
+
// Extract options object if present (last arg with special keys)
|
|
44
|
+
const lastArg = args[args.length - 1];
|
|
45
|
+
const isOptionsObject = lastArg && typeof lastArg === 'object' &&
|
|
46
|
+
(lastArg.hint || lastArg.context || lastArg.details);
|
|
47
|
+
|
|
48
|
+
const options = isOptionsObject ? args.pop() : {};
|
|
49
|
+
const regularArgs = args;
|
|
50
|
+
|
|
51
|
+
// Display main error message
|
|
52
|
+
console.log(chalk.red('❌'), chalk.red(message), ...regularArgs);
|
|
53
|
+
|
|
54
|
+
// Display context if provided - helps identify the scope of the error
|
|
55
|
+
if (options.context) {
|
|
56
|
+
console.log(chalk.red(' Context:'), chalk.gray(options.context));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Display technical details if provided - useful for debugging
|
|
60
|
+
if (options.details) {
|
|
61
|
+
const detailsStr = typeof options.details === 'object'
|
|
62
|
+
? JSON.stringify(options.details, null, 2)
|
|
63
|
+
: String(options.details);
|
|
64
|
+
console.log(chalk.red(' Details:'), chalk.gray(detailsStr));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Display actionable hint if provided - most valuable for authors
|
|
68
|
+
if (options.hint) {
|
|
69
|
+
console.log(chalk.yellow(' 💡 How to fix:'), chalk.yellow(options.hint));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Collect message with all context for healthcheck/JSON output
|
|
73
|
+
messageCollector.addMessage('error', message, [...regularArgs, options]);
|
|
74
|
+
|
|
75
|
+
console.log(); // Extra newline for readability
|
|
20
76
|
}
|
|
21
77
|
|
|
22
78
|
/**
|
|
23
79
|
* Warning messages - yellow with warning symbol
|
|
80
|
+
*
|
|
81
|
+
* Enhanced warning logging with optional context and actionable guidance.
|
|
82
|
+
*
|
|
83
|
+
* @param {string} message - The main warning message
|
|
84
|
+
* @param {...any} args - Additional arguments. Can include:
|
|
85
|
+
* - Regular values (strings, numbers, objects) for message formatting
|
|
86
|
+
* - An options object (if last arg is object with 'hint', 'context', or 'details' keys):
|
|
87
|
+
* - hint: Actionable suggestion for addressing the warning
|
|
88
|
+
* - context: Additional context about where/why the warning occurred
|
|
89
|
+
* - details: Technical details or related information
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* Logger.warn('Using fallback configuration', {
|
|
93
|
+
* context: 'specs.json missing optional field',
|
|
94
|
+
* hint: 'Add "output_path" to specs.json for better control',
|
|
95
|
+
* details: 'Using default: ./docs'
|
|
96
|
+
* });
|
|
24
97
|
*/
|
|
25
98
|
static warn(message, ...args) {
|
|
26
|
-
|
|
99
|
+
// Extract options object if present (last arg with special keys)
|
|
100
|
+
const lastArg = args[args.length - 1];
|
|
101
|
+
const isOptionsObject = lastArg && typeof lastArg === 'object' &&
|
|
102
|
+
(lastArg.hint || lastArg.context || lastArg.details);
|
|
103
|
+
|
|
104
|
+
const options = isOptionsObject ? args.pop() : {};
|
|
105
|
+
const regularArgs = args;
|
|
106
|
+
|
|
107
|
+
// Display main warning message
|
|
108
|
+
console.log(chalk.keyword('orange')('❗'), chalk.yellow(message), ...regularArgs);
|
|
109
|
+
|
|
110
|
+
// Display context if provided - helps identify the scope of the warning
|
|
111
|
+
if (options.context) {
|
|
112
|
+
console.log(chalk.yellow(' Context:'), chalk.gray(options.context));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Display technical details if provided - useful for understanding the situation
|
|
116
|
+
if (options.details) {
|
|
117
|
+
const detailsStr = typeof options.details === 'object'
|
|
118
|
+
? JSON.stringify(options.details, null, 2)
|
|
119
|
+
: String(options.details);
|
|
120
|
+
console.log(chalk.yellow(' Details:'), chalk.gray(detailsStr));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Display actionable hint if provided - helps authors improve their spec
|
|
124
|
+
if (options.hint) {
|
|
125
|
+
console.log(chalk.cyan(' 💡 Suggestion:'), chalk.cyan(options.hint));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Collect message with all context for healthcheck/JSON output
|
|
129
|
+
messageCollector.addMessage('warn', message, [...regularArgs, options]);
|
|
130
|
+
|
|
131
|
+
console.log(); // Extra newline for readability
|
|
27
132
|
}
|
|
28
133
|
|
|
29
|
-
/**
|
|
30
|
-
* Info messages - blue with info symbol
|
|
31
|
-
*/
|
|
32
134
|
static info(message, ...args) {
|
|
33
|
-
console.log(chalk.blue('
|
|
135
|
+
console.log(chalk.blue('📋'), chalk.blue(message), ...args);
|
|
136
|
+
messageCollector.addMessage('info', message, args);
|
|
137
|
+
|
|
138
|
+
console.log(); // Extra newline for readability
|
|
34
139
|
}
|
|
35
140
|
|
|
36
141
|
/**
|
|
@@ -38,6 +143,9 @@ class Logger {
|
|
|
38
143
|
*/
|
|
39
144
|
static process(message, ...args) {
|
|
40
145
|
console.log(chalk.cyan('🔄'), chalk.cyan(message), ...args);
|
|
146
|
+
messageCollector.addMessage('process', message, args);
|
|
147
|
+
|
|
148
|
+
console.log(); // Extra newline for readability
|
|
41
149
|
}
|
|
42
150
|
|
|
43
151
|
/**
|
|
@@ -45,13 +153,19 @@ class Logger {
|
|
|
45
153
|
*/
|
|
46
154
|
static debug(message, ...args) {
|
|
47
155
|
console.log(chalk.gray('🔍'), chalk.gray(message), ...args);
|
|
156
|
+
messageCollector.addMessage('debug', message, args);
|
|
157
|
+
|
|
158
|
+
console.log(); // Extra newline for readability
|
|
48
159
|
}
|
|
49
160
|
|
|
50
161
|
/**
|
|
51
162
|
* Highlight important data - magenta
|
|
52
163
|
*/
|
|
53
164
|
static highlight(message, ...args) {
|
|
54
|
-
console.log(chalk.blue('
|
|
165
|
+
console.log(chalk.blue('📋'), chalk.blue(message), ...args);
|
|
166
|
+
messageCollector.addMessage('highlight', message, args);
|
|
167
|
+
|
|
168
|
+
console.log(); // Extra newline for readability
|
|
55
169
|
}
|
|
56
170
|
|
|
57
171
|
/**
|
|
@@ -59,6 +173,9 @@ class Logger {
|
|
|
59
173
|
*/
|
|
60
174
|
static separator() {
|
|
61
175
|
console.log(chalk.gray('═'.repeat(60)));
|
|
176
|
+
messageCollector.addMessage('separator', '═'.repeat(60), []);
|
|
177
|
+
|
|
178
|
+
console.log(); // Extra newline for readability
|
|
62
179
|
}
|
|
63
180
|
|
|
64
181
|
/**
|
|
@@ -67,7 +184,11 @@ class Logger {
|
|
|
67
184
|
static progress(current, total, message) {
|
|
68
185
|
const percentage = Math.round((current / total) * 100);
|
|
69
186
|
const bar = '█'.repeat(Math.floor(percentage / 5)) + '░'.repeat(20 - Math.floor(percentage / 5));
|
|
70
|
-
|
|
187
|
+
const progressMessage = `[${bar}] ${percentage}% ${message}`;
|
|
188
|
+
console.log(chalk.cyan(`📊 ${progressMessage}`));
|
|
189
|
+
messageCollector.addMessage('progress', progressMessage, [current, total]);
|
|
190
|
+
|
|
191
|
+
console.log(); // Extra newline for readability
|
|
71
192
|
}
|
|
72
193
|
}
|
|
73
194
|
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Message collector for capturing console output from menu operations
|
|
3
|
+
*
|
|
4
|
+
* This module wraps the Logger to intercept and store all console messages
|
|
5
|
+
* produced during menu [1] (render) and menu [4] (collect external references)
|
|
6
|
+
* operations, storing them in JSON format for consumption by healthchecks.
|
|
7
|
+
*
|
|
8
|
+
* The captured messages are stored in `.cache/console-messages.json` with
|
|
9
|
+
* structured metadata including:
|
|
10
|
+
* - timestamp: ISO timestamp of when the message was logged
|
|
11
|
+
* - type: success, error, warn, info, process, highlight, debug, separator
|
|
12
|
+
* - message: the actual message text
|
|
13
|
+
* - operation: which menu operation triggered this (render or collectExternalReferences)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs-extra');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Message collection state
|
|
21
|
+
*/
|
|
22
|
+
const messageStore = {
|
|
23
|
+
messages: [],
|
|
24
|
+
currentOperation: null,
|
|
25
|
+
isCollecting: false
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Start collecting messages for a specific operation
|
|
30
|
+
* @param {string} operation - Operation name ('render' or 'collectExternalReferences')
|
|
31
|
+
*/
|
|
32
|
+
function startCollecting(operation) {
|
|
33
|
+
messageStore.isCollecting = true;
|
|
34
|
+
messageStore.currentOperation = operation;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Stop collecting messages
|
|
39
|
+
*/
|
|
40
|
+
function stopCollecting() {
|
|
41
|
+
messageStore.isCollecting = false;
|
|
42
|
+
messageStore.currentOperation = null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Add a message to the collection
|
|
47
|
+
* @param {string} type - Message type (success, error, warn, etc.)
|
|
48
|
+
* @param {string} message - Message text
|
|
49
|
+
* @param {Array} args - Additional arguments passed to logger
|
|
50
|
+
*/
|
|
51
|
+
function addMessage(type, message, args = []) {
|
|
52
|
+
if (!messageStore.isCollecting) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const messageEntry = {
|
|
57
|
+
timestamp: new Date().toISOString(),
|
|
58
|
+
type,
|
|
59
|
+
message: String(message),
|
|
60
|
+
operation: messageStore.currentOperation,
|
|
61
|
+
additionalData: args.length > 0 ? args.map(arg => String(arg)) : undefined
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
messageStore.messages.push(messageEntry);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Save collected messages to JSON file
|
|
69
|
+
* Each run creates a fresh file, replacing any existing messages.
|
|
70
|
+
*
|
|
71
|
+
* @param {string} [outputPath] - Optional custom output path
|
|
72
|
+
* @returns {Promise<string>} Path to the saved file
|
|
73
|
+
*/
|
|
74
|
+
async function saveMessages(outputPath) {
|
|
75
|
+
const cacheDir = path.join(process.cwd(), '.cache');
|
|
76
|
+
const defaultPath = path.join(cacheDir, 'console-messages.json');
|
|
77
|
+
const filePath = outputPath || defaultPath;
|
|
78
|
+
|
|
79
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
80
|
+
|
|
81
|
+
const output = {
|
|
82
|
+
metadata: {
|
|
83
|
+
generatedAt: new Date().toISOString(),
|
|
84
|
+
totalMessages: messageStore.messages.length,
|
|
85
|
+
operations: [...new Set(messageStore.messages.map(m => m.operation))],
|
|
86
|
+
messagesByType: messageStore.messages.reduce((acc, msg) => {
|
|
87
|
+
acc[msg.type] = (acc[msg.type] || 0) + 1;
|
|
88
|
+
return acc;
|
|
89
|
+
}, {})
|
|
90
|
+
},
|
|
91
|
+
messages: messageStore.messages
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
await fs.writeJson(filePath, output, { spaces: 2 });
|
|
95
|
+
|
|
96
|
+
return filePath;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Clear all collected messages
|
|
101
|
+
*/
|
|
102
|
+
function clearMessages() {
|
|
103
|
+
messageStore.messages = [];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get current messages (without saving)
|
|
108
|
+
* @returns {Array} Array of message objects
|
|
109
|
+
*/
|
|
110
|
+
function getMessages() {
|
|
111
|
+
return [...messageStore.messages];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get statistics about collected messages
|
|
116
|
+
* @returns {Object} Statistics object
|
|
117
|
+
*/
|
|
118
|
+
function getStatistics() {
|
|
119
|
+
return {
|
|
120
|
+
total: messageStore.messages.length,
|
|
121
|
+
byType: messageStore.messages.reduce((acc, msg) => {
|
|
122
|
+
acc[msg.type] = (acc[msg.type] || 0) + 1;
|
|
123
|
+
return acc;
|
|
124
|
+
}, {}),
|
|
125
|
+
byOperation: messageStore.messages.reduce((acc, msg) => {
|
|
126
|
+
if (msg.operation) {
|
|
127
|
+
acc[msg.operation] = (acc[msg.operation] || 0) + 1;
|
|
128
|
+
}
|
|
129
|
+
return acc;
|
|
130
|
+
}, {}),
|
|
131
|
+
isCollecting: messageStore.isCollecting,
|
|
132
|
+
currentOperation: messageStore.currentOperation
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = {
|
|
137
|
+
startCollecting,
|
|
138
|
+
stopCollecting,
|
|
139
|
+
addMessage,
|
|
140
|
+
saveMessages,
|
|
141
|
+
clearMessages,
|
|
142
|
+
getMessages,
|
|
143
|
+
getStatistics
|
|
144
|
+
};
|
|
@@ -109,12 +109,14 @@ const templateTags = {
|
|
|
109
109
|
* Pattern breakdown:
|
|
110
110
|
* - ^def$ → Exact match for "def" (definition)
|
|
111
111
|
* - ^ref$ → Exact match for "ref" (reference)
|
|
112
|
+
* - ^iref$ → Exact match for "iref" (inline reference - copies existing term)
|
|
112
113
|
* - ^xref → Starts with "xref" (external reference)
|
|
113
114
|
* - ^tref → Starts with "tref" (typed reference)
|
|
114
115
|
*
|
|
115
116
|
* Examples:
|
|
116
117
|
* - "def" → matches
|
|
117
118
|
* - "ref" → matches
|
|
119
|
+
* - "iref" → matches
|
|
118
120
|
* - "xref" → matches
|
|
119
121
|
* - "tref" → matches
|
|
120
122
|
* - "xref:spec,term" → matches (starts with xref)
|
|
@@ -122,7 +124,7 @@ const templateTags = {
|
|
|
122
124
|
* Flags:
|
|
123
125
|
* - i: case-insensitive matching
|
|
124
126
|
*/
|
|
125
|
-
terminology: /^def$|^ref$|^xref|^tref$/i
|
|
127
|
+
terminology: /^def$|^ref$|^iref$|^xref|^tref$/i
|
|
126
128
|
};
|
|
127
129
|
|
|
128
130
|
/**
|
package/templates/template.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<meta name="author" content="${author}">
|
|
9
9
|
<meta property="spec-up-t:github-repo-info" content="${githubRepoInfo}">
|
|
10
10
|
<link rel="icon" href="${specFavicon}" type="image/x-icon">
|
|
11
|
-
<meta name="generator" content="Spec-Up-T"
|
|
11
|
+
<meta name="generator" content="Spec-Up-T">
|
|
12
12
|
<title>${title}</title>
|
|
13
13
|
|
|
14
14
|
${assetsHead}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.min.css" rel="stylesheet">
|
|
20
20
|
</head>
|
|
21
21
|
|
|
22
|
-
<body
|
|
22
|
+
<body>
|
|
23
23
|
<!-- Skip to content link for accessibility -->
|
|
24
24
|
<a href="#content" class="screen-reader-text">Skip to content</a>
|
|
25
25
|
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
</button>
|
|
129
129
|
|
|
130
130
|
<a id="logo" href="${specLogoLink}">
|
|
131
|
-
<img class="d-print-none m-1" src="${specLogo}" alt=""
|
|
131
|
+
<img class="d-print-none m-1" src="${specLogo}" alt="">
|
|
132
132
|
</a>
|
|
133
133
|
|
|
134
134
|
<!-- Spacer to push the following elements to the right -->
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
<div class="d-flex align-items-center service-menu d-print-none">
|
|
139
139
|
|
|
140
140
|
<!-- Settings side menu -->
|
|
141
|
-
<button id="repo_settings"
|
|
141
|
+
<button id="repo_settings" class="btn btn-sm btn-outline-secondary ms-2" type="button"
|
|
142
142
|
data-bs-toggle="offcanvas" data-bs-target="#offcanvasSettings" aria-controls="offcanvasSettings">
|
|
143
143
|
<svg class="bi" width="1em" height="1em" aria-hidden="true">
|
|
144
144
|
<use href="#gear-wide-connected"></use>
|
|
@@ -249,7 +249,7 @@
|
|
|
249
249
|
|
|
250
250
|
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasSettings" aria-labelledby="offcanvasSettingsLabel">
|
|
251
251
|
<div class="offcanvas-header">
|
|
252
|
-
<h5 class="offcanvas-title mt-0" id="
|
|
252
|
+
<h5 class="offcanvas-title mt-0" id="offcanvasSettingsLabel">Settings</h5>
|
|
253
253
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
|
254
254
|
</div>
|
|
255
255
|
<div class="offcanvas-body p-0">
|
|
@@ -259,7 +259,7 @@
|
|
|
259
259
|
aria-label="Enter GitHub Token">
|
|
260
260
|
Enter GitHub Token
|
|
261
261
|
</button>
|
|
262
|
-
<button id="repo_issues" issue-count animate class="btn btn-menu-item m-0 mb-1 border-start-0 border-end-0"
|
|
262
|
+
<button id="repo_issues" data-issue-count data-animate class="btn btn-menu-item m-0 mb-1 border-start-0 border-end-0"
|
|
263
263
|
type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasIssues"
|
|
264
264
|
aria-controls="offcanvasIssues">
|
|
265
265
|
Issues
|