File size: 3,055 Bytes
cbf89ee b6bed80 75137c7 6c8fc4b cbf89ee b6bed80 | 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 | /**
* Utility functions and helpers
*/
import { CsvParseResult, CsvRow } from '../types/index.ts';
// Export user utilities
export * from './user.utils.ts';
// Export analysis utilities
export * from './analysis.utils.ts';
// Export cache utilities
export * from './cache.utils.ts';
/**
* Debounce function - delays execution until after wait time
*/
export function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number
): (...args: Parameters<T>) => void {
let timeout: NodeJS.Timeout | null = null;
return function executedFunction(...args: Parameters<T>) {
const later = () => {
timeout = null;
func(...args);
};
if (timeout) clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
/**
* Format error message from API error or string
*/
export function formatError(error: unknown): string {
if (typeof error === 'string') return error;
if (error && typeof error === 'object' && 'message' in error) {
return String(error.message);
}
return 'An unexpected error occurred';
}
/**
* Sleep/delay utility
*/
export function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Check if value is empty (null, undefined, empty string, empty array, empty object)
*/
export function isEmpty(value: unknown): boolean {
if (value == null) return true;
if (typeof value === 'string') return value.trim().length === 0;
if (Array.isArray(value)) return value.length === 0;
if (typeof value === 'object') return Object.keys(value).length === 0;
return false;
}
/**
* Parse a CSV string into headers and rows.
* Supports quoted fields and trims whitespace around values.
*/
export function parseCsv(content: string): CsvParseResult {
const lines = content.split(/\r?\n/).filter((line) => line.trim().length > 0);
if (lines.length === 0) {
return { headers: [], rows: [] };
}
const parseLine = (line: string): string[] => {
const cells: string[] = [];
let current = '';
let inQuotes = false;
for (let i = 0; i < line.length; i += 1) {
const char = line[i];
const nextChar = line[i + 1];
if (char === '"') {
if (inQuotes && nextChar === '"') {
current += '"';
i += 1;
} else {
inQuotes = !inQuotes;
}
} else if (char === ',' && !inQuotes) {
cells.push(current.trim());
current = '';
} else {
current += char;
}
}
cells.push(current.trim());
return cells;
};
const headers = parseLine(lines[0]).map((header, index) =>
header ? header : `column_${index + 1}`
);
const rows: CsvRow[] = lines.slice(1).map((line) => {
const values = parseLine(line);
const row: CsvRow = {};
headers.forEach((header, idx) => {
row[header] = values[idx]?.trim() ?? '';
});
return row;
});
return {
headers,
rows: rows.filter((row) =>
Object.values(row).some((value) => value !== undefined && value !== '')
),
};
}
|