Skip to content

Commit 7af4092

Browse files
committed
feat: restructred json/csv into common DateFormat type
makes it easier to generalize other future features over different dataformats BREAKING CHANGE: exports in package has changed
1 parent 49cb111 commit 7af4092

9 files changed

Lines changed: 74 additions & 17 deletions

File tree

src/csv.ts renamed to src/dataformat/csv.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { GeneratorFlow } from './generator-flow';
1+
import { GeneratorFlow } from '../generator-flow';
2+
import { DataFormat } from './domain';
23

34
type Quote = '"' | "'";
45

@@ -47,6 +48,10 @@ function readCSVLine(chars: string[], startAt: number, delimiter: string = ','):
4748
return [i + 1, values];
4849
}
4950

51+
function writeCSVLine(line: Array<string>, delimiter: string = ','): string {
52+
return line.map((it) => `"${it.replace(/"/g, '\\"')}"`).join(delimiter);
53+
}
54+
5055
export function* parseCSV(content: string, delimiter: string = ','): Generator<Array<string>, void> {
5156
const chars = content.split('');
5257
let charPointer = 0;
@@ -68,3 +73,22 @@ export function parseCSVToFlow(content: string, delimiter: string = ','): Genera
6873
export function parseCSVSync(content: string, delimiter: string = ','): Array<string[]> {
6974
return parseCSVToFlow(content, delimiter).toArray();
7075
}
76+
77+
export function* writeAsCSV(content: Array<string[]>, delimiter: string = ','): Generator<string, void> {
78+
for (const line of content) {
79+
yield writeCSVLine(line, delimiter);
80+
}
81+
}
82+
83+
export function writeAsCSVSync(content: Array<string[]>, delimiter: string = ','): string {
84+
return new GeneratorFlow<string>(() => writeAsCSV(content, delimiter)).toArray().join('\n');
85+
}
86+
87+
export const CsvFormat: DataFormat<unknown> = {
88+
serialize(object: Array<string[]>, delimiter: string = ','): string {
89+
return writeAsCSVSync(object, delimiter);
90+
},
91+
deserialize(content: string, delimiter: string = ','): Array<string[]> {
92+
return parseCSVSync(content, delimiter);
93+
}
94+
};

src/dataformat/domain.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface DataFormat<T> {
2+
serialize(object: T): string;
3+
deserialize(object: string): T;
4+
}

src/dataformat/json.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { DataFormat } from './domain';
2+
3+
export function serialize(object: unknown): string {
4+
return typeof object === 'string' ? object : JSON.stringify(object, null, 2);
5+
}
6+
7+
export function deserialize<T>(content: string): T {
8+
return JSON.parse(content);
9+
}
10+
11+
export const JsonFormat: DataFormat<unknown> = {
12+
serialize,
13+
deserialize
14+
};

src/file.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as fs from 'fs';
22
import { WriteStream } from 'fs';
33
import * as fsP from 'fs/promises';
4-
import { serialize, deserialize } from './json';
4+
import { serialize, deserialize } from './dataformat/json';
55

66
export async function read(path: string): Promise<string> {
77
return fsP.readFile(path, 'utf8');

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export * as File from './file';
2-
export * as CSV from './csv';
3-
export * as Json from './json';
2+
export * as CSV from './dataformat/csv';
3+
export * as Json from './dataformat/json';
44
export { GeneratorFlow } from './generator-flow';

src/json.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as fs from 'fs';
2-
import { test, assertThat } from './test-lib';
3-
import { parseCSVSync } from '../src/csv';
2+
import { test, assertThat } from '../test-lib';
3+
import { parseCSVSync, CsvFormat } from '../../src/dataformat/csv';
44

55
test('should be able to parse super simple csv', () => {
66
const csv = parseCSVSync('h1,h2\nv1,v2\nv3,v4');
@@ -42,3 +42,17 @@ test('should be able to parse csv with multilne content', () => {
4242
'csv content should match'
4343
);
4444
});
45+
46+
test('should implement csv dataformat', () => {
47+
const data = [
48+
['Header 1', 'Header "2"'],
49+
['value 1', 'value "2"'],
50+
['value 2', "value '2'"],
51+
['value 3', 'value \n"2\n and more']
52+
];
53+
54+
const textual: string = CsvFormat.serialize(data);
55+
const recreated = CsvFormat.deserialize(textual);
56+
57+
assertThat(data, recreated, 'recreated json is similar to original data');
58+
});
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { test, assertThat } from './test-lib';
2-
import { serialize, deserialize } from '../src/json';
1+
import { test, assertThat } from '../test-lib';
2+
import { serialize, deserialize, JsonFormat } from '../../src/dataformat/json';
33

44
test('should not try to serialize string', () => {
55
assertThat('hei', serialize('hei'), 'string is the same');
@@ -14,3 +14,11 @@ test('should deserialize json', () => {
1414
assertThat(['content'], deserialize('[\n "content"\n]'), 'array is deserialized');
1515
assertThat({ content: 'hei' }, deserialize('{\n "content": "hei"\n}'), 'object is deserialized');
1616
});
17+
18+
test('should implement json dataformat', () => {
19+
const data = { content: 'hello', value: { content: 'world' } };
20+
const json: string = JsonFormat.serialize(data);
21+
const recreated = JsonFormat.deserialize(json);
22+
23+
assertThat(data, recreated, 'recreated json is similar to original data');
24+
});

test/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
import './csv.test';
2-
import './json.test';
1+
import './dataformat/csv.test';
2+
import './dataformat/json.test';

0 commit comments

Comments
 (0)