/// !doc /// ## Stream transform for CSV files /// /// `import { csvParser, csvFormatter } from 'f-streams'` /// import { Reader } from '../reader'; import { Writer } from '../writer'; import * as lines from './lines'; /// * `transform = csvParser(options)` /// creates a parser transform. The following options can be set: /// - `sep`: the field separator, comma by default export interface ParserOptions { sep?: string; encoding?: string; } export function parser(options?: ParserOptions) { const opts = options || {}; const sep = opts.sep || ','; return (reader: Reader, writer: Writer) => { const rd = reader.transform(lines.parser()); const keys = (rd.read() || '').split(sep); rd.forEach(line => { // ignore empty line (we get one at the end if file is terminated by newline) if (line.length === 0) return; const values = line.split(sep); const obj: any = {}; keys.forEach((key, i) => { obj[key] = values[i]; }); writer.write(obj); }); }; } /// * `transform = csvFormatter(options)` /// creates a formatter transform. The following options can be set: /// - `sep`: the field separator, comma by default /// - `eol`: the end of line marker (`\n` or `\r\n`) export interface FormatterOptions { sep?: string; eol?: string; } export function formatter(options?: FormatterOptions) { const opts = options || {}; const sep = opts.sep || ','; const eol = opts.eol || '\n'; return (reader: Reader, writer: Writer) => { let obj = reader.read(); if (!obj) return; const keys = Object.keys(obj); writer.write(keys.join(sep) + eol); do { const values = keys.map(key => obj[key]); writer.write(values.join(sep) + eol); } while ((obj = reader.read()) !== undefined); }; }