All files / if-run/builtins/util csv-helpers.ts

100% Statements 45/45
100% Branches 7/7
100% Functions 9/9
100% Lines 39/39

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 985x 5x 5x 5x   5x   5x     5x         5x 44x 44x 12x   32x               5x 30x 8x 4x         4x     22x 3x             5x 89x         5x 41x 6x   6x 45x 45x     6x     35x             5x 37x 4x     32x           5x 26x 26x           22x   4x 4x      
import {readFile} from 'fs/promises';
import axios from 'axios';
import {parse} from 'csv-parse/sync';
import {ERRORS} from '@grnsft/if-core/utils';
 
import {STRINGS} from '../../config';
 
const {FILE_FETCH_FAILED, FILE_READ_FAILED, MISSING_CSV_COLUMN} = STRINGS;
 
const {FetchingFileError, ReadFileError, MissingCSVColumnError, CSVParseError} =
  ERRORS;
 
/**
 * Checks if given string is URL.
 */
export const isURL = (filepath: string) => {
  try {
    new URL(filepath);
    return true;
  } catch (error) {
    return false;
  }
};
 
/**
 * Checks if given `filepath` is url, then tries to fetch it.
 * Otherwise tries to read file.
 */
export const retrieveFile = async (filepath: string) => {
  if (isURL(filepath)) {
    const {data} = await axios.get(filepath).catch(error => {
      throw new FetchingFileError(
        FILE_FETCH_FAILED(filepath, error.response.message)
      );
    });
 
    return data;
  }
 
  return readFile(filepath).catch(error => {
    throw new ReadFileError(FILE_READ_FAILED(filepath, error));
  });
};
 
/**
 * Checks if value is invalid: `undefined`, `null` or an empty string, then sets `nan` instead.
 */
export const setNanValue = (value: any) =>
  value === null || value === '' ? 'nan' : value;
 
/**
 * Converts empty values to `nan`.
 */
export const nanifyEmptyValues = (object: any) => {
  if (typeof object === 'object') {
    const keys = Object.keys(object);
 
    keys.forEach(key => {
      const value = object[key];
      object[key] = setNanValue(value);
    });
 
    return object;
  }
 
  return setNanValue(object);
};
 
/**
 * If `field` is missing from `object`, then reject with error.
 * Otherwise nanify empty values and return data.
 */
export const fieldAccessor = (field: string, object: any) => {
  if (!(`${field}` in object)) {
    throw new MissingCSVColumnError(MISSING_CSV_COLUMN(field));
  }
 
  return nanifyEmptyValues(object[field]);
};
 
/**
 * Parses CSV file.
 */
export const parseCSVFile = (file: string | Buffer) => {
  try {
    const parsedCSV: any[] = parse(file, {
      columns: true,
      skip_empty_lines: true,
      cast: true,
    });
 
    return parsedCSV;
  } catch (error: any) {
    console.error(error);
    throw new CSVParseError(error);
  }
};