easy-cli-framework
Version:
A framework for building CLI applications that are robust and easy to maintain. Supports theming, configuration files, interactive prompts, and more.
204 lines (203 loc) • 7.16 kB
TypeScript
import { EasyCLITheme } from '../themes';
/**
* A mapping for a CSV field to a field in an object.
* @template TType The type of the field after transformation.
*
* @interface CsvFieldMapping
*
* @property {string[]} aliases The aliases for the field in the CSV.
* @property {boolean} required If the field is required or not.
* @property {function} transform The function to transform the value from the CSV. (Default: value => value)
* @property {boolean} allowEmpty If the field can be empty or not. (Default: false)
* @property {TType} defaultValue The default value for the field. (Default: undefined)
*/
export type CsvFieldMapping<TType = any> = {
aliases: string[];
required: boolean;
transform?: (value: string) => any | Promise<any>;
allowEmpty?: boolean;
defaultValue?: TType;
};
/**
* A mapping of fields in an object to their CSV field mappings.
*
* @interface CsvFieldMappings
*
* @template TObject The object type to map to.
*
* @property {keyof TObject} The name of the field in the object.
* @property {CsvFieldMapping<TObject[keyof TObject]>} The rules for mapping the field.
*
*/
export type CsvFieldMappings<TObject> = Record<keyof TObject, CsvFieldMapping<TObject[keyof TObject]>>;
/**
* A mapping of CSV columns to their object fields that they map to.
*
* @interface ObjectDataMapper
*
* @template TObject The output object type.
* @template TFileObject The CSV file object type.
*
* @property {keyof TFileObject} The column in the CSV file.
* @property {keyof TObject[]} The fields in the object that the column maps to.
*
* @example
* ```typescript
* {
* 'Username': ['username'],
* 'Identifier': ['id'],
* 'First name': ['firstName', 'firstInital'],
* }
* ```
*/
export type ObjectDataMapper<TObject, TFileObject> = Record<keyof TFileObject, (keyof TObject)[]>;
/**
* The settings for the CSV Mapper instance.
*
* @interface CsvMapperOptions
*
* @property {CsvFieldMappings<TObject>} mappings The field mappings for the CSV file.
* @property {boolean} interactive If it should interactively ask for other field mappings. (Default: false)
* @property {boolean} discardOriginalFields If it should discard any fields that are not mapped or not. If false, will store them with their name from the CSV. (Default: true)
* @property {EasyCLITheme} theme The theme to use for the prompts.
* @property {boolean} validate If it should validate the data against the mappings. (Default: true)
*
* @example
* ```typescript
* {
* mappings: {
* username: {
* aliases: ['Username'],
* required: true,
* transform: value => value,
* },
* ...
* },
* interactive?: true, // If it should interactively ask for other field mappings. (Default: false)
* discardOriginalFields?: true, // If it should discard any fields that are not mapped or not. If false, will store them with their name from the CSV along with the mapped fields (Default: true)
* theme?: EasyCLITheme | null, // The theme to use for the prompts.
* validate?: true, // If it should validate the data against the mapping rules, if errors are detected it will throw an error (Default: true)
* }
* ```
*/
export type CsvMapperOptions<TObject extends Record<string, any>> = {
interactive?: boolean;
discardOriginalFields?: boolean;
mappings: CsvFieldMappings<TObject>;
theme?: EasyCLITheme | null;
validate?: boolean;
};
export declare class CSVMapper<TObject extends Record<string, any> = Record<string, any>, TFileObject extends Record<string, any> = Record<string, any>> {
private mappings;
private interactive;
private discardOriginalFields;
private theme;
private validate;
/**
* Create a new CSV Mapper instance.
*
* @param options The options for the CSV Mapper.
* @returns {CSVMapper<TObject, TFileObject>} A new CSV Mapper instance.
*
* @example
* const csvProcessor = new CSVMapper({
* mappings: {
* username: {
* aliases: ['Username'],
* required: true,
* transform: value => value,
* },
* id: {
* aliases: ['Identifier'],
* required: true,
* transform: value => parseInt(value),
* },
* lastName: {
* aliases: [],
* required: true,
* transform: value => value,
* },
* firstName: {
* aliases: ['First name', 'First Name'],
* required: true,
* transform: value => value,
* },
* firstInital: {
* aliases: ['First name', 'First Name'],
* required: true,
* transform: value => value[0],
* },
* },
* interactive: true,
* });
*/
constructor(options: CsvMapperOptions<TObject>);
/**
* Read a CSV file and parse it into an array of objects.
*
* @param path The path to the CSV file to read.
* @throws {Error} If the file is not found or there is an error reading the file.
*
* @returns The parsed CSV file as an array of objects.
*/
private readFile;
/**
* Prompt the user for missing fields in the mappings.
*
* @param missingFields What fields are missing from the mappings
* @param unmappedColumns What columns are not mapped
*
* @returns Additional mappings for the CSV columns
*/
private promptMissingFields;
/**
* Process a CSV file and return the data as an array of transformed objects.
*
* @param path The path to the CSV file to process
*
* @throws {Error} If there are validation errors in the CSV file and the validate option is set to true.
*
* @returns {Promise<TObject[]>} The data from the CSV file as an array of transformed objects
*
* @example
* ```typescript
* const csvProcessor = new CSVMapper({...});
* const data = await csvProcessor.processFile('./username.csv');
* ```
*/
processFile: (path: string) => Promise<TObject[]>;
/**
* Validation for the CSV file, comparing the fields to the mappings.
*
* @param rows The rows to validate
* @param fieldMap The field map to use for validation
*
* @throws {Error} If there are validation errors in the CSV file
*/
private validateData;
/**
* Transforn a row from the CSV file into the correct output.
*
* @param row The row data to transform
* @param fieldMapping How to map the fields from the CSV to the object
*
* @returns {Promise<TObject>} A normalized row object
*/
private transformRow;
/**
* Build a field map from the columns found in the CSV file.
*
* @param {(keyof TFileObject)[]} columns The columns found in the CSV file
*
* @returns {ObjectDataMapper<TObject, TFileObject>} A field map that maps the CSV columns to the object fields
*/
private buildFieldMap;
/**
* Find the mapped field for a CSV column.
*
* @param {keyof TFileObject} field The field to find the mapped field for
*
* @returns {(keyof TObject[])} The mapped fields for the CSV column
*/
private findMappedField;
}