csv-rxjs-kit
Version:
A kit of RxJS operators to handle CSV formatted (RFC 4180, MIME Type 'text/csv') data.
180 lines (179 loc) • 8.54 kB
TypeScript
import { OperatorFunction, MonoTypeOperatorFunction } from 'rxjs';
/** Basic CSV-record.
*
* `csvRecord` datatype represents single MIME Type 'text/csv' [RFC 4180](https://www.ietf.org/rfc/rfc4180.txt) data record.
* Any first record of a CSV-record stream might be header record.
*
* Every CSV-record just an array of string. Every empty field is an empty string. Empty records are empty arrays.
*/
export declare type csvRecord = string[];
/** CSV data converter function type.
* @typeParam T - source data type
* @typeParam R - result data type
* @param src - source data object
* @param names - field names form header record
*/
export declare type csvDataConverter<T, R> = (src: T, names?: string[]) => R;
/**
* CSV-record validator function type.
* @param csvRecord - CSV-record to validate
* @param isHeader - CSV-record type
* @returns validated CSV-record
* @throws any validation errors
*/
export declare type csvRecordValidator = (rec: csvRecord, isHeader: boolean) => csvRecord;
/** Object builder function type. */
export declare type csvBuilder<T> = csvDataConverter<csvRecord, T>;
/** CSV-record extractor function type. */
export declare type csvExtractor<T> = csvDataConverter<T, csvRecord>;
/**
* CSV formatter RxJS operator.
*
* Returns an Observable that converts to text every `csvRecord` emitted by source Observable.
* Output text data is formatted as MIME Type 'text/csv' [RFC 4180](https://www.ietf.org/rfc/rfc4180.txt).
*
* Parameter `opt.delimiter` sets line breaks type, default is `CRLF`.
*
* Parameter `opt.last_break` adds optional line delimiter after the last record.
*
* Parameter `opt.force_quote` adds quotation to every item.
*
* @param opt - options
*/
export declare function csvStringify(opt?: {
delimiter?: '\r\n' | '\n';
last_break?: boolean;
force_quote?: boolean;
}): OperatorFunction<csvRecord, string>;
/**
* CSV parser RxJS operator.
*
* Returns an Obsrevable that parses text emitted by source Observable and converts it to `csvRecord`s.
* Input text should be MIME Type 'text/csv' as described is [RFC 4180](https://www.ietf.org/rfc/rfc4180.txt).
*
* All parse errors are reported as `SyntaxError` using an Observer's `error()` method.
*/
export declare function csvParse(): OperatorFunction<string, csvRecord>;
/**
* Removes empty records.
*
* Returns an Observable that removes all empty records emitted by source Observable.
*/
export declare function csvDropEmpty(): MonoTypeOperatorFunction<csvRecord>;
/**
* Removes header record.
*
* Returns an Observable that removes header `csvRecord` (the first data item) emitted by source Observable.
* There is no dedicated tagging for header `csvRecord` so one must be sure the source Observable emits header.
*
* @typeParam T - the main data type, might be csvRecord or any arbitrary data type
*/
export declare function csvDropHeader<T>(): OperatorFunction<T | csvRecord, T>;
/**
* Injects a header record.
*
* Returns an Observable that emits header record and then mirrors source Observable.
* Inserted `csvRecord` will be interpreted as a header `csvRecord` by other operators if they are instructed to.
*
* @typeParam T - the main stream type
* @param header - header record value
*/
export declare function csvInjectHeader<T>(header: csvRecord): OperatorFunction<T, T | csvRecord>;
/**
* Validates a record.
*
* Returns an Observable that uses `validator` to check/modify every `csvRecord` emitted by source Observable.
*
* To remove invalid records one can use `validator` to convert them to empty records and then use `csvDropEmpty` operator.
*
* @param hdr - does source Obsrvable emit header 'csvRecord'?
* @param validator - function to validate a 'csvRecord'
* @throws everything that `validator` throws
*/
export declare function csvValidateRecord(hdr: boolean, validator: csvRecordValidator): MonoTypeOperatorFunction<csvRecord>;
/**
* Creates `csvRecord` for data array.
*
* Returns an Observable that converts every array item emitted by source Observable to `csvRecord`.
* The operator calls `String(...)` for every defined item in the input data array, undefined items are replaced by `''`.
*
* It doesn't matter if source Observable emits header record. The operator's conversion procedure doesn't affect a header record.
*
* If you need different behavior and/or have different input data type use `csvConvert()` and custom `csvExtractor<T>`.
*/
export declare function csvFromArray(): OperatorFunction<unknown[], csvRecord>;
/**
* Converts an item using provided data converter function, uses header record to extract names.
*
* Returns an Observable that uses `prj` function to convert items emitted by source Observable.
*
* If `hdr === true` the operator interprets first item emitted by source Observable as a header record
* and uses the record's data as names in subsequent `prj` calls.
* The header records is reemitted, don't forget to remove it to clean up the data item stream.
*
* If `hdr === false` no names available to `prj` function and every record emitted by source Observable is converted.
*
* @typeParam T - input object type
* @typeParam R - output object type
* @param hdr - does source Observable emit header 'csvRecord'?
* @param prj - function to convert object
* @throws `RangeError` if `prj` argument is invalid
*/
export declare function csvConvert<T, R>(hdr: false, prj: csvDataConverter<T, R>): OperatorFunction<T, R>;
export declare function csvConvert<T, R>(hdr: true, prj: csvDataConverter<T, R>): OperatorFunction<csvRecord | T, csvRecord | R>;
/**
* Justifies record length, can be is used with `csvValidateRecord()`.
*
* Returns `csvRecordValidator` that justifies record length according to header length.
* According to RFC 4180 'each line should contain the same number of fields throughout the file'
* hence any changes to bad sized records violate the RFC.
*
* Parameter `opt.length` sets default length of a record. A header record length (if available)
* overrides `opt.length` value. If `opt.length` is not set and header record hasn't been available,
* no records are altered.
*
* Parameter `opt.skip_empty` instructs to skip empty records, **violates RFC 4180**
*
* Parameter `opt.repair` instructs to repair bad sized records, **violates RFC 4180**
*
* Parameter `opt.filler` sets repair mode. If `opt.filler` is defined bad sized record is filled up
* or cut to the header length. If `opt.filler` is undefined invalid record is replaced with an empty record.
*
* @param opt - validation options
*/
export declare function csvJustifier(opt?: {
length?: number;
skip_empty?: boolean;
repair?: boolean;
filler?: string;
}): csvRecordValidator;
/**
* Creates an object upon `csvRecord`.
*
* Returns `csvBuilder<Record<string, string>>` that creates an object using properties names array and `rec` data as values.
* Every data item in `csvRecords` is added to created object. Data item index is used to select property name in `names` array.
* If no such name exists then argument `extra` is used to generate property name for index `i`.
*
* If `extra` is function, then propery name is `<extra>(<i>)`.
* If `extra` is string, then property name is `<extra><i>`.
* If `extra` is undefined, then property name is `_<i>`.
*
* Can be used in `csvConvert()` to create simple objects.
*
* @see csvConvert()
*
* @param extra - property name generator for unlisted properties
*/
export declare function csvAssembler(extra?: string | ((index: number) => string)): csvBuilder<Record<string, string>>;
/** Returns an array of alphabetically sorted enumerable properties of an object. */
export declare function csvPropNames(obj: Record<string, unknown>): csvRecord;
/**
* Creates an CSV record upon object.
*
* Returns `csvExtractor<Record<string, unknown>>` that creates an CSV record using properties names array and `obj` as values.
* Every listed on `names` property's value is received from `obj` and stored in the record. Undefined values replaced by `''`.
* If `extra === true` all non listed object properties values are added to the record in alphabetical order after the listed ones.
*
* @param extra - add non listed properties values
*/
export declare function csvPropValues(extra?: boolean): csvExtractor<Record<string, unknown>>;