UNPKG

@bakes/dastardly-csv

Version:
107 lines 3.4 kB
// CSV-specific utility functions /** * Escape a field value for CSV output. * If the field contains the delimiter, quotes, or newlines, it will be quoted. * Quotes within the field are doubled per RFC 4180. * * @param value - The field value to escape * @param delimiter - The delimiter character (e.g., ',', '\t', '|') * @returns Escaped field value (quoted if necessary) */ export function escapeField(value, delimiter) { // Empty string doesn't need quoting if (value.length === 0) { return ''; } // Check if field needs quoting const needsQuote = value.includes(delimiter) || value.includes('"') || value.includes('\n') || value.includes('\r'); if (!needsQuote) { return value; } // Quote the field and double any internal quotes const escaped = value.replace(/"/g, '""'); return `"${escaped}"`; } /** * Unescape a CSV field value. * Removes surrounding quotes and converts doubled quotes to single quotes. * * @param value - The field value to unescape * @returns Unescaped field value */ export function unescapeField(value) { // If field is quoted, remove quotes and unescape doubled quotes if (value.startsWith('"') && value.endsWith('"')) { const unquoted = value.slice(1, -1); return unquoted.replace(/""/g, '"'); } // Unquoted field - return as-is return value; } /** * Determine if a field value needs quoting based on the quote strategy. * * @param value - The field value * @param delimiter - The delimiter character * @param quoting - The quote strategy * @returns True if the field should be quoted */ export function needsQuoting(value, delimiter, quoting) { switch (quoting) { case 'all': return true; case 'none': return false; case 'nonnumeric': { // Check if value is numeric const isNumeric = /^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/.test(value); if (isNumeric) { return false; } // Non-numeric values need quoting return true; } case 'needed': default: { // Quote if contains delimiter, quotes, newlines, or spaces // Spaces require quoting per RFC 4180 for proper parsing return (value.includes(delimiter) || value.includes('"') || value.includes('\n') || value.includes('\r') || value.includes(' ')); } } } /** * Parse a CSV number from text. * Handles integers, floats, exponential notation, and negative zero. * * @param text - The number text to parse * @returns Parsed number value */ export function parseCSVNumber(text) { return parseFloat(text); } /** * Normalize line endings in text to the specified style. * * @param text - The text to normalize * @param style - The line ending style ('crlf' or 'lf') * @returns Text with normalized line endings */ export function normalizeLineEnding(text, style) { if (style === 'crlf') { // Convert all line endings to CRLF // First normalize CRLF to LF, then LF to CRLF return text.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n'); } else { // Convert all line endings to LF return text.replace(/\r\n/g, '\n'); } } //# sourceMappingURL=utils.js.map