All files / lib/visualizers utils.js

95.23% Statements 20/21
75% Branches 3/4
100% Functions 4/4
95.23% Lines 20/21

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            5x 5x                   210x                               8x                           11x 11x 9x   2x                       6x 6x 6x     6x   4x 4x   1x 1x   1x 1x         6x   1x      
import fs from 'fs-extra';
import chalk from 'chalk';
import { execSync } from 'child_process';
import path from 'path';
import { fileURLToPath } from 'url';
 
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
 
/**
 * Escapes HTML special characters to prevent XSS.
 * Replaces &, <, >, ", ' with their HTML entities.
 *
 * @param {any} str - The string to escape (will be converted to string)
 * @returns {string} - Escaped HTML-safe string
 */
export function escapeHtml(str) {
  return String(str)
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;');
}
 
/**
 * Escapes JSON string for safe embedding in <script> tags.
 * Prevents breaking out of script context and XSS attacks.
 *
 * @param {string} jsonString - The JSON string to escape
 * @returns {string} - Escaped JSON string safe for script embedding
 */
export function escapeJsonForScript(jsonString) {
  return jsonString
    .replace(/</g, '\\u003c') // Prevent </script> break
    .replace(/\u2028/g, '\\u2028') // Line separator
    .replace(/\u2029/g, '\\u2029'); // Paragraph separator
}
 
/**
 * Reads an HTML template file and returns its contents as a string.
 *
 * @param {string} filePath - Path to the template file
 * @returns {Promise<string>} - Template content as UTF-8 string
 * @throws {Error} - If file cannot be read, with chalk-formatted message
 */
export async function readTemplate(filePath) {
  try {
    const content = await fs.readFile(filePath, 'utf8');
    return content;
  } catch (err) {
    throw new Error(chalk.red(`Error reading template ${filePath}: ${err.message}`));
  }
}
 
/**
 * Opens a file in the system's default browser.
 * Cross-platform support: darwin (open), win32 (start), linux (xdg-open).
 *
 * @param {string} filePath - Path to the HTML file to open
 * @throws {Error} - If browser cannot be opened
 */
export function openBrowser(filePath) {
  try {
    const absolutePath = path.resolve(filePath);
    const url = `file://${absolutePath}`;
    let command;
 
    switch (process.platform) {
      case 'darwin':
        command = `open "${url}"`;
        break;
      case 'win32':
        command = `start "${url}"`;
        break;
      case 'linux':
        command = `xdg-open "${url}"`;
        break;
      default:
        command = `xdg-open "${url}"`;
    }
 
    execSync(command, { stdio: 'ignore' });
  } catch (err) {
    throw new Error(chalk.red(`Failed to open browser: ${err.message}`));
  }
}