@kksiuda/csv
v2.1.1
Published
Csv parsing and stringifying
Downloads
4
Readme
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
- string: string
- columns?: CsvColumns
- params?: CsvParams
- 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
- columns?: CsvColumns
- params?: CsvParams
- 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
- columns?: CsvColumns
- params?: CsvParams
- 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
- stream: Readable | Transform
- columns?: CsvColumns
- params?: CsvParams
- 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
- input
- stream: Readable | Transform
- columns?: CsvColumns
- params?: CsvParams
- output
- Promise of string
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
- stringify
- 'integer'
- stringify
- value is number and not NaN -> value.toFixed(0)
- else -> ''
- parse
- value -> parseInt(value, 10)
- stringify
- 'float'
- stringify
- value is number and not NaN -> value cast to string
- else -> ''
- parse
- value -> value * 1
- stringify
- '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
- stringify
- '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'
- parse
- 'text'
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