UNPKG

1.59 kBPlain TextView Raw
1import {Field} from './record';
2
3const DEFAULT_FIELD_DELIMITER = ',';
4const VALID_FIELD_DELIMITERS = [DEFAULT_FIELD_DELIMITER, ';'];
5
6export abstract class FieldStringifier {
7 constructor(public readonly fieldDelimiter: string) {}
8
9 abstract stringify(value?: Field): string;
10
11 protected isEmpty(value?: Field): boolean {
12 return typeof value === 'undefined' || value === null || value === '';
13 }
14
15 protected quoteField(field: string): string {
16 return `"${field.replace(/"/g, '""')}"`;
17 }
18}
19
20class DefaultFieldStringifier extends FieldStringifier {
21 stringify(value?: Field): string {
22 if (this.isEmpty(value)) return '';
23 const str = String(value);
24 return this.needsQuote(str) ? this.quoteField(str) : str;
25 }
26
27 private needsQuote(str: string): boolean {
28 return str.includes(this.fieldDelimiter) || str.includes('\n') || str.includes('"');
29 }
30}
31
32class ForceQuoteFieldStringifier extends FieldStringifier {
33 stringify(value?: Field): string {
34 return this.isEmpty(value) ? '' : this.quoteField(String(value));
35 }
36}
37
38export function createFieldStringifier(fieldDelimiter: string = DEFAULT_FIELD_DELIMITER, alwaysQuote = false) {
39 _validateFieldDelimiter(fieldDelimiter);
40 return alwaysQuote ? new ForceQuoteFieldStringifier(fieldDelimiter) : new DefaultFieldStringifier(fieldDelimiter);
41}
42
43function _validateFieldDelimiter(delimiter: string): void {
44 if (VALID_FIELD_DELIMITERS.indexOf(delimiter) === -1) {
45 throw new Error(`Invalid field delimiter \`${delimiter}\` is specified`);
46 }
47}