2.1.1 • Published 2 years ago

@kksiuda/csv v2.1.1

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Overview

No dependency CSV parsing and stringifying, synchronously or via stream, typed or untyped

Installation

yarn install @kksiuda/csv

or

npm install @kksiuda/csv

API

parseCsv

Parses string synchronously.

  • input
  • output
    • when columns are specified it returns array of type inferred from columns, otherwise array of records

Example

import { parseCsv, CsvColumns } from '@kksiuda/csv';

const csvString = 'a,b\n1,2\n';
const columns = {
  a: 'integer',
  b: { type: 'string' },
} satisfies CsvColumns;
console.log(parseCsv(csvString)); // [ { a: '1', b: '2' } ]
console.log(parseCsv(csvString, columns)); // [ { a: 1, b: '2' } ]

stringifyCsv

Stringifies array of records. Note: if columns are not specified the columns will be inferred from the first row.

  • input
    • records: when columns are specified array of type inferred from columns, otherwise array of records
    • columns?: CsvColumns
    • params?: CsvParams
  • output
    • string

Example

import { stringifyCsv } from '@kksiuda/csv';

const records = [{ a: 1 }, { a: 1, b: 2 }];
const columns = {
  a: 'integer',
  b: { type: 'integer' },
} satisfies CsvColumns;
console.log(stringifyCsv(records)); // 'a\n1\n'
console.log(stringifyCsv(records, columns)); // 'a,b\n1,\n1,2\n'

createParseCsvStream

Creates a transform stream for parsing csv.

  • input
  • output
    • Transform stream that takes in strings and outputs records in objectMode

Example

import { createParseCsvStream, createStringifyCsvStream } from '@kksiuda/csv';
import { createReadStream, createWriteStream } from 'node:fs';
import { pipeline } from 'node:stream';
const readable = createReadStream('./input.csv');
const writable = createWriteStream('./output.csv');
const parseStream = createParseCsvStream();
const stringifyStream = createStringifyCsvStream();
pipeline(
  readable,
  parseStream,
  stringifyStream,
  writable,
  (err) => (err ? console.log(err) : console.log('done')) // 'done'
);

createStringifyCsvStream

Creates a transform stream for stringifying csv.

  • input
  • output
    • Transform stream that takes records in objectMode and outputs strings

Example: see above

parseCsvFromStream

Takes an string input stream and asynchronously parses csv

  • input
  • output
    • Promise of array of types specified in columns when defined or array of records otherwise

Example:

import { parseCsvFromStream } from '@kksiuda/csv';
import { createReadStream } from 'node:fs';

const readable = createReadStream('./input.csv');
(async () => {
  console.log(await parseCsvFromStream(readable)); // array of records
})();

stringifyCsvFromStream

Takes an objectMode input stream and asynchronously stringifies csv

Example:

import { stringifyCsvFromStream, createParseCsvStream } from '@kksiuda/csv';
import { createReadStream } from 'node:fs';

const readable = createReadStream('./input.csv');
const parseStream = createParseCsvStream();

(async () => {
  readable.pipe(parseStream);
  console.log(await stringifyCsvFromStream(parseStream)); // csv string
})();

Types

CsvColumns

type CsvColumns<T extends Record<string, any> = Record<string, any>> = {
  [P in keyof T]?: CsvColumn<T, P> | CsvColumnType;
};
type CsvColumn<T extends Record<string, any>, P extends keyof T = keyof T> = {
  type: CsvColumnType;
  nullable?: boolean;
  stringify?: (val: T[P]) => string;
  parse?: (str: string) => T[P];
  header?: string;
  index?: number;
};

Note: when parsing empty strings will always be parsed as either null or undefined when useNullForEmpty is true

  • prop: property on the object; when header is not specified it will be used as a header when stringifying csv
  • type:
    • 'text'
      • stringify
        • value is string -> value
        • value is boolean or truthy -> value cast to string
        • else -> ''
      • parse
        • value -> value
    • 'integer'
      • stringify
        • value is number and not NaN -> value.toFixed(0)
        • else -> ''
      • parse
        • value -> parseInt(value, 10)
    • 'float'
      • stringify
        • value is number and not NaN -> value cast to string
        • else -> ''
      • parse
        • value -> value * 1
    • 'percentage'
      • stringify
      • value is number and not NaN -> value * 100 cast to string with '%' at the end
      • else -> ''
      • parse
        • value -> parseInt(value, 10) / 100
    • 'boolean'
      • stringify
        • value is not undefined and not null and falsy -> 'FALSE'
        • value is truthy -> 'TRUE'
        • else -> ''
      • parse
        • value is '0', 'N', 'n', 'false', 'FALSE', 'False', 'no', 'NO', or 'No' -> false
        • else -> true
    • 'date', 'datetime', 'datetimes', 'timestamp'
      • parses using dateClass supplied in csvParams; see for defaults below
      • parse
        • value can be parsed by casting to built-in Date -> number
      • stringify
        • value is NaN or not of type number -> ''
        • date: 'YYYY-MM-DD'
        • datetime: 'YYYY-MM-DD HH:mm'
        • datetimes: 'YYYY-MM-DD HH:mm:SS'
        • timestamp: 'YYYY-MM-DD HH:mm:SS.sss'
    • 'custom'
      • parse
        • uses parse function; defaults to 'string'
      • stringify
        • uses stringify function; defaults to 'string'
  • stringify
    • function that takes value of prop from the record and returns a string
    • only used when type is 'custom'
  • parse

    • function that takes csv string and returns the value of prop to go on the record
    • only used when type is 'custom'
  • header

    • represents header in the csv
    • when not specified defaults to prop

CsvParams

interface CsvParams {
  delimiter?: string;
  quote?: string | null;
  escapeQuote?: string | null;
  rowSeparator?: string;
  ignoreUnderscoredProps?: boolean;
  dateOptions?: {
    locale?: string;
    timezoneOffset?: number | 'local';
    dst?: 'none' | 'eu' | 'us';
  };
  dateFormats?: {
    date?: string;
    dateTime?: string;
    dateTimeSeconds?: string;
    timestamp?: string;
  };
  dateClass?: DateConstructor;
  noHeader?: boolean;
  useNullForEmpty?: boolean;
  titleCaseHeaders?: boolean;
  preserveCarriageReturn?: boolean;
}

Note: when specifying non-default dateOptions or dateFormats dateClass needs to point to a constructor from an external library (see p00dle/datex), otherwise it will throw an error

Note: when both escape and escapeQuote are null no values are considered as quoted in both parsing and stringifying

  • delimiter - string that separates values in a row; default: ','
  • quote - string that wraps the value when value contains delimiter, quote, or rowSeparator; default: '"'
  • escapeQuote - string that is used for escaping quote; default: '""'
  • rowSeparator - string that separates rows; default: '\n'
  • ignoreUnderscoredProps - when columns are not specified during the stringifying process all props starting with an underscore will be ignored; has no effect on parsing; default: false
  • dateOptions
    • locale - determines things like month names, ordinals etc.
    • timezoneOffset - timezone offset in hours or 'local' to use machine's local timezone offset
    • dst - the daylight savings system used to determine when daylight savings are applied
  • dateFormats
    • specify date format for specific column types
  • dateClass - specify when using an external library
  • noHeader - when true headers will not be emitted when stringifying; when parsing columns will be assigned using the order of columns (throws when columns are undefined); default: false
  • useNullForEmpty - when true empty values will be parsed as null, otherwise as undefined; default: true
  • titleCaseHeaders - when columns are not specified the headers will be parsed from camel case to title case; only applies to stringifying; default: false
  • preserveCarriageReturn - when true carriage return (\r) are not removed and considered valid characters; default: false
1.2.0

2 years ago

1.3.0

2 years ago

2.1.1

2 years ago

2.1.0

2 years ago

2.0.0

2 years ago

1.1.0

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago

1.1.2

2 years ago

0.9.10

3 years ago

0.9.9

3 years ago

0.9.8

3 years ago

0.9.7

3 years ago

0.9.6

3 years ago

0.9.5

3 years ago

0.9.4

3 years ago