/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ /** * Safely replaces text with literal strings, avoiding ECMAScript GetSubstitution issues. * Escapes $ characters to prevent template interpretation. */ export function safeLiteralReplace( str: string, oldString: string, newString: string, ): string { if (oldString === '' || !str.includes(oldString)) { return str; } if (!newString.includes('$')) { return str.replaceAll(oldString, newString); } const escapedNewString = newString.replaceAll('$', '$$$$'); return str.replaceAll(oldString, escapedNewString); } /** * Checks if a Buffer is likely binary by testing for the presence of a NULL byte. * The presence of a NULL byte is a strong indicator that the data is not plain text. * @param data The Buffer to check. * @param sampleSize The number of bytes from the start of the buffer to test. * @returns True if a NULL byte is found, false otherwise. */ export function isBinary( data: Buffer | null | undefined, sampleSize = 512, ): boolean { if (!data) { return false; } const sample = data.length > sampleSize ? data.subarray(0, sampleSize) : data; for (const byte of sample) { // The presence of a NULL byte (0x00) is one of the most reliable // indicators of a binary file. Text files should not contain them. if (byte === 0) { return true; } } // If no NULL bytes were found in the sample, we assume it's text. return false; } /** * Detects the line ending style of a string. * @param content The string content to analyze. * @returns '\r\n' for Windows-style, '\n' for Unix-style. */ export function detectLineEnding(content: string): '\r\n' | '\n' { // If a Carriage Return is found, assume Windows-style endings. // This is a simple but effective heuristic. return content.includes('\r\n') ? '\r\n' : '\n'; } /** * Truncates a string to a maximum length, appending a suffix if truncated. * @param str The string to truncate. * @param maxLength The maximum length of the string. * @param suffix The suffix to append if truncated (default: '...[TRUNCATED]'). * @returns The truncated string. */ export function truncateString( str: string, maxLength: number, suffix = '...[TRUNCATED]', ): string { if (str.length <= maxLength) { return str; } return str.slice(0, maxLength) + suffix; }