All files / src/utils message-collector.js

100% Statements 31/31
80% Branches 12/15
100% Functions 12/12
100% Lines 31/31

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145                              15x 15x         15x                     20x 20x             58x 58x                   93x 56x     37x         12x     37x                     4x 4x 4x   4x   4x       8x   8x 8x           4x   4x             57x               13x               8x     7x 7x     7x 7x   7x             15x                  
/**
 * @file Message collector for capturing console output from menu operations
 * 
 * This module wraps the Logger to intercept and store all console messages
 * produced during menu [1] (render) and menu [4] (collect external references)
 * operations, storing them in JSON format for consumption by healthchecks.
 * 
 * The captured messages are stored in `.cache/console-messages.json` with
 * structured metadata including:
 * - timestamp: ISO timestamp of when the message was logged
 * - type: success, error, warn, info, process, highlight, debug, separator
 * - message: the actual message text
 * - operation: which menu operation triggered this (render or collectExternalReferences)
 */
 
const fs = require('fs-extra');
const path = require('node:path');
 
/**
 * Message collection state
 */
const messageStore = {
    messages: [],
    currentOperation: null,
    isCollecting: false
};
 
/**
 * Start collecting messages for a specific operation
 * @param {string} operation - Operation name ('render' or 'collectExternalReferences')
 */
function startCollecting(operation) {
    messageStore.isCollecting = true;
    messageStore.currentOperation = operation;
}
 
/**
 * Stop collecting messages
 */
function stopCollecting() {
    messageStore.isCollecting = false;
    messageStore.currentOperation = null;
}
 
/**
 * Add a message to the collection
 * @param {string} type - Message type (success, error, warn, etc.)
 * @param {string} message - Message text
 * @param {Array} args - Additional arguments passed to logger
 */
function addMessage(type, message, args = []) {
    if (!messageStore.isCollecting) {
        return;
    }
 
    const messageEntry = {
        timestamp: new Date().toISOString(),
        type,
        message: String(message),
        operation: messageStore.currentOperation,
        additionalData: args.length > 0 ? args.map(arg => String(arg)) : undefined
    };
 
    messageStore.messages.push(messageEntry);
}
 
/**
 * Save collected messages to JSON file
 * Each run creates a fresh file, replacing any existing messages.
 * 
 * @param {string} [outputPath] - Optional custom output path
 * @returns {Promise<string>} Path to the saved file
 */
async function saveMessages(outputPath) {
    const cacheDir = path.join(process.cwd(), '.cache');
    const defaultPath = path.join(cacheDir, 'console-messages.json');
    const filePath = outputPath || defaultPath;
 
    await fs.ensureDir(path.dirname(filePath));
 
    const output = {
        metadata: {
            generatedAt: new Date().toISOString(),
            totalMessages: messageStore.messages.length,
            operations: [...new Set(messageStore.messages.map(m => m.operation))],
            messagesByType: messageStore.messages.reduce((acc, msg) => {
                acc[msg.type] = (acc[msg.type] || 0) + 1;
                return acc;
            }, {})
        },
        messages: messageStore.messages
    };
 
    await fs.writeJson(filePath, output, { spaces: 2 });
 
    return filePath;
}
 
/**
 * Clear all collected messages
 */
function clearMessages() {
    messageStore.messages = [];
}
 
/**
 * Get current messages (without saving)
 * @returns {Array} Array of message objects
 */
function getMessages() {
    return [...messageStore.messages];
}
 
/**
 * Get statistics about collected messages
 * @returns {Object} Statistics object
 */
function getStatistics() {
    return {
        total: messageStore.messages.length,
        byType: messageStore.messages.reduce((acc, msg) => {
            acc[msg.type] = (acc[msg.type] || 0) + 1;
            return acc;
        }, {}),
        byOperation: messageStore.messages.reduce((acc, msg) => {
            Eif (msg.operation) {
                acc[msg.operation] = (acc[msg.operation] || 0) + 1;
            }
            return acc;
        }, {}),
        isCollecting: messageStore.isCollecting,
        currentOperation: messageStore.currentOperation
    };
}
 
module.exports = {
    startCollecting,
    stopCollecting,
    addMessage,
    saveMessages,
    clearMessages,
    getMessages,
    getStatistics
};