Source

src/csvToJsonAsync.js

/* globals CsvFormatError, FileOperationError */
'use strict';

const fileUtils = require('./util/fileUtils');
const csvToJson = require('./csvToJson');
const { InputValidationError } = require('./util/errors');

/**
 * Asynchronous CSV to JSON converter
 * Proxies configuration to sync instance but provides async file I/O methods
 * @category 3-Async
 */
class CsvToJsonAsync {
    /**
     * Constructor initializes proxy to sync csvToJson instance
     */
    constructor() {
        // Proxy the configuration methods to the sync instance
        this.csvToJson = csvToJson;
    }

    /**
     * Enable or disable automatic type formatting for values
     * @param {boolean} active - Whether to format values by type
     * @returns {this} For method chaining
     */
    formatValueByType(active) {
        this.csvToJson.formatValueByType(active);
        return this;
    }

    /**
     * Enable or disable support for RFC 4180 quoted fields
     * @param {boolean} active - Whether to support quoted fields
     * @returns {this} For method chaining
     */
    supportQuotedField(active) {
        this.csvToJson.supportQuotedField(active);
        return this;
    }

    /**
     * Set the field delimiter character
     * @param {string} delimiter - Character(s) to use as field separator
     * @returns {this} For method chaining
     */
    fieldDelimiter(delimiter) {
        this.csvToJson.fieldDelimiter(delimiter);
        return this;
    }

    /**
     * Configure whitespace handling in header field names
     * @param {boolean} active - If true, removes all whitespace; if false, only trims edges
     * @returns {this} For method chaining
     */
    trimHeaderFieldWhiteSpace(active) {
        this.csvToJson.trimHeaderFieldWhiteSpace(active);
        return this;
    }

    /**
     * Set the row index where CSV headers are located
     * @param {number} indexHeader - Zero-based row index containing headers
     * @returns {this} For method chaining
     */
    indexHeader(indexHeader) {
        this.csvToJson.indexHeader(indexHeader);
        return this;
    }

    /**
     * Configure sub-array parsing for special field values
     * @param {string} delimiter - Bracket character (default: '*')
     * @param {string} separator - Item separator within brackets (default: ',')
     * @returns {this} For method chaining
     */
    parseSubArray(delimiter = '*', separator = ',') {
        this.csvToJson.parseSubArray(delimiter, separator);
        return this;
    }

    /**
     * Set a mapper function to transform each row after conversion
     * @param {function(object, number): (object|null)} mapperFn - Function receiving (row, index) that returns transformed row or null to filter
     * @returns {this} For method chaining
     */
    mapRows(mapperFn) {
        this.csvToJson.mapRows(mapperFn);
        return this;
    }

    /**
     * Set file encoding for reading CSV files
     * @param {string} encoding - Node.js supported encoding (e.g., 'utf8', 'latin1')
     * @returns {this} For method chaining
     */
    encoding(encoding) {
        this.csvToJson.encoding = encoding;
        return this;
    }

    /**
     * Read a CSV file and write parsed JSON to an output file (async)
     * @param {string} fileInputName - Path to input CSV file
     * @param {string} fileOutputName - Path to output JSON file
     * @returns {Promise<void>}
     * @throws {FileOperationError} If file operations fail
     * @throws {CsvFormatError} If CSV is malformed
     */
    async generateJsonFileFromCsv(fileInputName, fileOutputName) {
        const jsonStringified = await this.getJsonFromCsvStringified(fileInputName);
        await fileUtils.writeFileAsync(jsonStringified, fileOutputName);
    }

    /**
     * Read a CSV file and return parsed data as stringified JSON (async)
     * @param {string} fileInputName - Path to input CSV file
     * @returns {Promise<string>} JSON stringified array of objects
     * @throws {FileOperationError} If file read fails
     * @throws {CsvFormatError} If CSV is malformed
     */
    async getJsonFromCsvStringified(fileInputName) {
        const json = await this.getJsonFromCsvAsync(fileInputName);
        return JSON.stringify(json, undefined, 1);
    }

    /**
     * Main async API method for reading CSV and returning parsed JSON
     * Supports reading from file path or parsing CSV string content
     * @param {string} inputFileNameOrCsv - File path or CSV string content
     * @param {object} options - Configuration options
     * @param {boolean} options.raw - If true, treats input as CSV string; if false, reads from file
     * @returns {Promise<Array<object>>} Array of objects representing CSV rows
     * @throws {InputValidationError} If input is invalid
     * @throws {FileOperationError} If file read fails
     * @throws {CsvFormatError} If CSV is malformed
     * @example
     * const csvToJson = require('convert-csv-to-json');
     * const data = await csvToJson.getJsonFromCsvAsync('resource/input.csv');
     * console.log(data);
     */
    async getJsonFromCsvAsync(inputFileNameOrCsv, options = {}) {
        if (inputFileNameOrCsv === null || inputFileNameOrCsv === undefined) {
            throw new InputValidationError(
                'inputFileNameOrCsv',
                'string (file path) or CSV string content',
                `${typeof inputFileNameOrCsv}`,
                'Either provide a valid file path or CSV content as a string.'
            );
        }

        if (options.raw) {
            if (inputFileNameOrCsv === '') {
                return [];
            }
            return this.csvToJson.csvToJson(inputFileNameOrCsv);
        }

        const parsedCsv = await fileUtils.readFileAsync(inputFileNameOrCsv, this.csvToJson.encoding || 'utf8');
        return this.csvToJson.csvToJson(parsedCsv);
    }

    /**
     * Parse CSV string to JSON array (async)
     * @param {string} csvString - CSV content as string
     * @param {object} options - Configuration options (default: { raw: true })
     * @returns {Promise<Array<object>>} Array of objects representing CSV rows
     * @throws {CsvFormatError} If CSV is malformed
     * @example
     * const csvToJson = require('convert-csv-to-json');
     * const data = await csvToJson.csvStringToJsonAsync('name,age\nAlice,30');
     * console.log(data);
     */
    csvStringToJsonAsync(csvString, options = { raw: true }) {
        return this.getJsonFromCsvAsync(csvString, options);
    }

    /**
     * Parse CSV string to stringified JSON (async)
     * @param {string} csvString - CSV content as string
     * @returns {Promise<string>} JSON stringified array of objects
     * @throws {CsvFormatError} If CSV is malformed
     * @example
     * const csvToJson = require('convert-csv-to-json');
     * const jsonString = await csvToJson.csvStringToJsonStringifiedAsync('name,age\nAlice,30');
     * console.log(jsonString);
     */
    async csvStringToJsonStringifiedAsync(csvString) {
        const json = await this.csvStringToJsonAsync(csvString);
        return JSON.stringify(json, undefined, 1);
    }
}

module.exports = new CsvToJsonAsync();