csv-for-you
Version:
CSV parser. Supports all nodeJS versions.
454 lines (414 loc) • 14.4 kB
text/typescript
// ============================================
// Type Definitions
// ============================================
export type LineEdit = {
data: Record<string, string | number | null>;
lineNumber: number
};
export type DeleteOptions = {
rowNumber?: number;
rowsToDelete?: number;
reportToConsole?: boolean
};
export type ParseOptions = {
arraySeparator?: string;
objectSeparator?: string;
lineAsArray?: boolean;
fileAsArray?: boolean;
returnAsString?: string[];
innerCallbacks?: boolean;
};
export type ParseCallbacks = {
lineCallback?: (line: unknown) => unknown;
fileCallback?: (file: unknown) => unknown;
arrayCallback?: (arr: unknown[]) => unknown;
objectCallback?: (obj: Record<string, unknown>) => unknown;
numberCallback?: (num: number) => unknown;
stringCallback?: (str: string) => unknown;
};
export type ParseResult = Record<string, unknown>[] | Record<string, unknown>;
export type AddRowOptions = { lineNumber?: number };
export type FileOptions = { overwrite?: boolean };
export type CreateFileOptions = { content?: string; overwrite?: boolean };
export type ReadFileOptions = { encoding?: BufferEncoding };
export type FileTreeOptions = { depth?: number; showHidden?: boolean };
export type FileOperationResult = { success: boolean; message: string };
export type ValidationOptions = {
checkHeaders?: boolean;
checkTypes?: boolean;
checkColumns?: boolean;
expectedHeaders?: string[] | null;
};
export type ValidationResult = {
valid: boolean;
errors: string[];
warnings: string[];
stats: {
totalRows: number;
totalColumns: number;
headers: string[];
};
};
export type BatchOperation = {
type: string;
file?: string;
source?: string;
destination?: string;
data?: Record<string, unknown>;
edit?: LineEdit;
options?: Record<string, unknown>;
};
export type BatchConfig = {
operations: BatchOperation[];
stopOnError?: boolean;
};
export type BatchResult = {
success: Array<{ operation: number; type: string; result: unknown }>;
failed: Array<{ operation: number; type: string; error: string }>;
total: number;
};
export type WatchOptions = {
onChange: (filePath: string, eventType: string) => void;
debounce?: number;
recursive?: boolean;
};
export type Watcher = {
stop: () => void;
};
export type Config = {
arraySeparator?: string;
objectSeparator?: string;
lineAsArray?: boolean;
fileAsArray?: boolean;
depth?: number;
showHidden?: boolean;
[key: string]: unknown;
};
// ============================================
// Imports
// ============================================
import { addRow as addRowJs } from './lib/rows/addRow.js';
import { deleteRows as deleteRowsJs } from './lib/rows/deleteRow';
import { editRow as editRowJs } from './lib/rows/editRow';
import { parse as parseJs } from './lib/parse';
import { moveFile as moveFileJs } from './lib/files/moveFile';
import { createFile as createFileJs } from './lib/files/createFile';
import { getFileTree as getFileTreeJs } from './lib/files/getFileTree';
import { copyFile as copyFileJs } from './lib/files/copyFile';
import { renameFile as renameFileJs } from './lib/files/renameFile';
import { deleteFile as deleteFileJs } from './lib/files/deleteFile';
import { readFile as readFileJs } from './lib/files/readFile';
import { appendToFile as appendToFileJs } from './lib/files/appendToFile';
import { validateCSV as validateCSVJs } from './lib/validateCSV';
import { batchOperations as batchOperationsJs } from './lib/batchOperations';
import { watchFile as watchFileJs, watchDirectory as watchDirectoryJs } from './lib/watch';
import { loadConfig as loadConfigJs, mergeConfig as mergeConfigJs, getDefaultConfig as getDefaultConfigJs } from './lib/config';
// ============================================
// CSV Operations with Validation
// ============================================
/**
* Add a row to a CSV file
* @param filePath - Path to the CSV file
* @param dataObject - Object containing column data
* @param options - Options for adding the row
* @throws {Error} If filePath is empty or dataObject is invalid
*/
export function addRow(
filePath: string,
dataObject: Record<string, string | number | null>,
options: AddRowOptions = {}
): Promise<void> {
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath must be a non-empty string');
}
if (!dataObject || typeof dataObject !== 'object') {
throw new Error('dataObject must be a valid object');
}
const opts = { lineNumber: 0, ...options };
return Promise.resolve(addRowJs(filePath, dataObject, opts) as any);
}
/**
* Delete rows from a CSV file
* @param filePath - Path to the CSV file
* @param options - Deletion options
* @throws {Error} If filePath is empty
*/
export function deleteRows(
filePath: string,
options: DeleteOptions = {}
): void {
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath must be a non-empty string');
}
return deleteRowsJs(filePath, options);
}
/**
* Edit a specific row in a CSV file
* @param filePath - Path to the CSV file
* @param edit - Edit details including line number and data
* @throws {Error} If filePath is empty or edit is invalid
*/
export function editRow(
filePath: string,
edit: LineEdit
): void {
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath must be a non-empty string');
}
if (!edit || !edit.data || typeof edit.lineNumber !== 'number') {
throw new Error('edit must contain data object and lineNumber');
}
if (edit.lineNumber < 1) {
throw new Error('lineNumber must be >= 1');
}
return editRowJs(filePath, edit);
}
/**
* Parse a CSV file
* @param filePath - Path to the CSV file
* @param options - Parsing options
* @param callbacks - Optional callbacks for data transformation
* @throws {Error} If filePath is empty
*/
export function parse(
filePath: string,
options: ParseOptions = {},
callbacks: ParseCallbacks = {}
): Promise<ParseResult> {
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath must be a non-empty string');
}
return parseJs(filePath, options as any, callbacks as any) as Promise<ParseResult>;
}
/**
* Validate CSV file structure and content
* @param filePath - Path to the CSV file
* @param options - Validation options
* @throws {Error} If filePath is empty
*/
export function validateCSV(
filePath: string,
options: ValidationOptions = {}
): Promise<ValidationResult> {
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath must be a non-empty string');
}
return validateCSVJs(filePath, options as any) as Promise<ValidationResult>;
}
// ============================================
// File Operations with Validation
// ============================================
/**
* Move a file from source to destination
* @param sourcePath - Source file path
* @param destinationPath - Destination file path
* @param options - Move options
* @throws {Error} If paths are empty
*/
export function moveFile(
sourcePath: string,
destinationPath: string,
options: FileOptions = {}
): Promise<FileOperationResult> {
if (!sourcePath || typeof sourcePath !== 'string') {
throw new Error('sourcePath must be a non-empty string');
}
if (!destinationPath || typeof destinationPath !== 'string') {
throw new Error('destinationPath must be a non-empty string');
}
return moveFileJs(sourcePath, destinationPath, options);
}
/**
* Copy a file from source to destination
* @param sourcePath - Source file path
* @param destinationPath - Destination file path
* @param options - Copy options
* @throws {Error} If paths are empty
*/
export function copyFile(
sourcePath: string,
destinationPath: string,
options: FileOptions = {}
): Promise<FileOperationResult> {
if (!sourcePath || typeof sourcePath !== 'string') {
throw new Error('sourcePath must be a non-empty string');
}
if (!destinationPath || typeof destinationPath !== 'string') {
throw new Error('destinationPath must be a non-empty string');
}
return copyFileJs(sourcePath, destinationPath, options);
}
/**
* Rename a file
* @param oldPath - Current file path
* @param newPath - New file path
* @param options - Rename options
* @throws {Error} If paths are empty
*/
export function renameFile(
oldPath: string,
newPath: string,
options: FileOptions = {}
): Promise<FileOperationResult> {
if (!oldPath || typeof oldPath !== 'string') {
throw new Error('oldPath must be a non-empty string');
}
if (!newPath || typeof newPath !== 'string') {
throw new Error('newPath must be a non-empty string');
}
return renameFileJs(oldPath, newPath, options);
}
/**
* Create a new file
* @param filePath - Path for the new file
* @param options - Creation options including content
* @throws {Error} If filePath is empty
*/
export function createFile(
filePath: string,
options: CreateFileOptions = {}
): Promise<FileOperationResult> {
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath must be a non-empty string');
}
return createFileJs(filePath, options);
}
/**
* Delete a file
* @param filePath - Path to the file to delete
* @throws {Error} If filePath is empty
*/
export function deleteFile(
filePath: string
): Promise<FileOperationResult> {
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath must be a non-empty string');
}
return deleteFileJs(filePath);
}
/**
* Read file contents
* @param filePath - Path to the file
* @param options - Read options including encoding
* @throws {Error} If filePath is empty
*/
export function readFile(
filePath: string,
options: ReadFileOptions = {}
): Promise<string> {
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath must be a non-empty string');
}
return readFileJs(filePath, options);
}
/**
* Append content to a file
* @param filePath - Path to the file
* @param content - Content to append
* @throws {Error} If filePath is empty
*/
export function appendToFile(
filePath: string,
content: string
): Promise<FileOperationResult> {
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath must be a non-empty string');
}
if (typeof content !== 'string') {
throw new Error('content must be a string');
}
return appendToFileJs(filePath, content);
}
/**
* Get directory tree structure
* @param targetPath - Path to directory or file
* @param options - Tree display options
* @throws {Error} If targetPath is empty
*/
export function getFileTree(
targetPath: string,
options: FileTreeOptions = {}
): Promise<string> {
if (!targetPath || typeof targetPath !== 'string') {
throw new Error('targetPath must be a non-empty string');
}
return getFileTreeJs(targetPath, options);
}
// ============================================
// Advanced Operations
// ============================================
/**
* Execute batch operations from configuration
* @param config - Batch configuration object or path to config file
* @throws {Error} If config is invalid
*/
export function batchOperations(
config: BatchConfig | string
): Promise<BatchResult> {
if (!config) {
throw new Error('config is required');
}
return batchOperationsJs(config as any) as Promise<BatchResult>;
}
/**
* Watch a file for changes
* @param filePath - Path to the file to watch
* @param options - Watch options including onChange callback
* @throws {Error} If filePath is empty or onChange is not provided
*/
export function watchFile(
filePath: string,
options: WatchOptions
): Watcher {
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath must be a non-empty string');
}
if (!options.onChange || typeof options.onChange !== 'function') {
throw new Error('onChange callback is required');
}
const opts = { debounce: 100, ...options };
return watchFileJs(filePath, opts as any) as Watcher;
}
/**
* Watch a directory for changes
* @param dirPath - Path to the directory to watch
* @param options - Watch options including onChange callback
* @throws {Error} If dirPath is empty or onChange is not provided
*/
export function watchDirectory(
dirPath: string,
options: WatchOptions
): Watcher {
if (!dirPath || typeof dirPath !== 'string') {
throw new Error('dirPath must be a non-empty string');
}
if (!options.onChange || typeof options.onChange !== 'function') {
throw new Error('onChange callback is required');
}
const opts = { recursive: true, debounce: 100, ...options };
return watchDirectoryJs(dirPath, opts as any) as Watcher;
}
// ============================================
// Configuration
// ============================================
/**
* Load configuration from file
* @param startDir - Directory to start searching for config (defaults to cwd)
*/
export function loadConfig(startDir?: string): Config | null {
return loadConfigJs(startDir) as Config | null;
}
/**
* Merge configuration with options
* @param config - Configuration from file
* @param options - Options from command/function call
*/
export function mergeConfig(config: Config | null, options: Config): Config {
return mergeConfigJs(config as any, options as any) as Config;
}
/**
* Get default configuration
*/
export function getDefaultConfig(): Config {
return getDefaultConfigJs() as Config;
}