Skip to content

Commit 68a9627

Browse files
committed
adding jsonLine convertion
1 parent 93dd366 commit 68a9627

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed

src/converters/toJsonLines.ts

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Readable } from 'stream';
2+
import { JsonLinesObject, ToJsonLinesOptions } from '../types';
3+
4+
export function toJsonLines(
5+
jsonArray: JsonLinesObject[],
6+
options?: ToJsonLinesOptions
7+
): string {
8+
if (!Array.isArray(jsonArray)) {
9+
throw new Error('Input must be an array of JSON objects.');
10+
}
11+
12+
if (!jsonArray.every(item => item && typeof item === 'object' && !Array.isArray(item))) {
13+
throw new Error('All elements in the array must be valid JSON objects.');
14+
}
15+
16+
const { indent = 0, excludeKeys = [] } = options || {};
17+
18+
return jsonArray
19+
.map(obj => {
20+
const filteredObj = { ...obj };
21+
excludeKeys.forEach(key => delete filteredObj[key]);
22+
return JSON.stringify(filteredObj, null, indent);
23+
})
24+
.join('\n');
25+
};
26+
27+
export function toJsonLinesStream(jsonArray: object[]): Readable {
28+
if (!Array.isArray(jsonArray)) {
29+
throw new Error('Input must be an array of JSON objects.');
30+
}
31+
32+
return Readable.from(jsonArray.map(obj => JSON.stringify(obj) + '\n'));
33+
};

tests/toJsonLines.test.ts

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { toJsonLines, toJsonLinesStream } from '../src/converters/toJsonLines';
2+
3+
describe('toJsonLines', () => {
4+
it('should convert an array of JSON objects to JSONLines format', () => {
5+
const jsonArray: Record<string, unknown>[] = [
6+
{ name: 'Alice', age: 25 },
7+
{ name: 'Bob', age: 30 },
8+
];
9+
10+
const expected = `{"name":"Alice","age":25}
11+
{"name":"Bob","age":30}`;
12+
const result = toJsonLines(jsonArray);
13+
14+
expect(result).toBe(expected);
15+
});
16+
17+
it('should handle nested objects and arrays', () => {
18+
const jsonArray: Record<string, unknown>[] = [
19+
{ name: 'Alice', details: { age: 25, city: 'New York' } },
20+
{ name: 'Bob', hobbies: ['reading', 'traveling'] },
21+
];
22+
23+
const expected = `{"name":"Alice","details":{"age":25,"city":"New York"}}
24+
{"name":"Bob","hobbies":["reading","traveling"]}`;
25+
const result = toJsonLines(jsonArray);
26+
27+
expect(result).toBe(expected);
28+
});
29+
30+
it('should handle different data types', () => {
31+
const jsonArray: Record<string, unknown>[] = [
32+
{ number: 42, boolean: true, nullValue: null, emptyObject: {} },
33+
];
34+
35+
const expected = `{"number":42,"boolean":true,"nullValue":null,"emptyObject":{}}`;
36+
const result = toJsonLines(jsonArray);
37+
38+
expect(result).toBe(expected);
39+
});
40+
41+
it('should handle an empty array', () => {
42+
const jsonArray: Record<string, unknown>[] = [];
43+
const expected = '';
44+
const result = toJsonLines(jsonArray);
45+
46+
expect(result).toBe(expected);
47+
});
48+
49+
it('should handle large volumes of data', () => {
50+
const jsonArray = Array.from({ length: 1000 }, (_, i) => ({ id: i }));
51+
52+
const result = toJsonLines(jsonArray);
53+
54+
expect(result.startsWith('{"id":0}')).toBe(true);
55+
expect(result.endsWith('{"id":999}')).toBe(true);
56+
});
57+
58+
it('should handle numeric keys in objects', () => {
59+
const jsonArray: Record<string, unknown>[] = [
60+
{ '123': 'value' },
61+
];
62+
63+
const expected = `{"123":"value"}`;
64+
const result = toJsonLines(jsonArray);
65+
66+
expect(result).toBe(expected);
67+
});
68+
69+
it('should exclude specified keys from the objects', () => {
70+
const jsonArray: Record<string, unknown>[] = [
71+
{ name: 'Alice', age: 25, city: 'New York' },
72+
{ name: 'Bob', age: 30, city: 'Los Angeles' },
73+
];
74+
75+
const options = { excludeKeys: ['city'] };
76+
const expected = `{"name":"Alice","age":25}
77+
{"name":"Bob","age":30}`;
78+
const result = toJsonLines(jsonArray, options);
79+
80+
expect(result).toBe(expected);
81+
});
82+
});
83+
84+
describe('toJsonLinesStream', () => {
85+
it('should create a readable stream of JSONLines', async () => {
86+
const jsonArray: Record<string, unknown>[] = [
87+
{ name: 'Alice', age: 25 },
88+
{ name: 'Bob', age: 30 },
89+
];
90+
91+
const stream = toJsonLinesStream(jsonArray);
92+
const chunks: string[] = [];
93+
94+
for await (const chunk of stream) {
95+
chunks.push(chunk.toString());
96+
}
97+
98+
const expected = `{"name":"Alice","age":25}
99+
{"name":"Bob","age":30}
100+
`;
101+
expect(chunks.join('')).toBe(expected);
102+
});
103+
104+
it('should handle nested objects and arrays in stream', async () => {
105+
const jsonArray: Record<string, unknown>[] = [
106+
{ name: 'Alice', details: { age: 25, city: 'New York' } },
107+
{ name: 'Bob', hobbies: ['reading', 'traveling'] },
108+
];
109+
110+
const stream = toJsonLinesStream(jsonArray);
111+
const chunks: string[] = [];
112+
113+
for await (const chunk of stream) {
114+
chunks.push(chunk.toString());
115+
}
116+
117+
const expected = `{"name":"Alice","details":{"age":25,"city":"New York"}}
118+
{"name":"Bob","hobbies":["reading","traveling"]}
119+
`;
120+
expect(chunks.join('')).toBe(expected);
121+
});
122+
123+
it('should handle an empty array and produce an empty stream', async () => {
124+
const jsonArray: Record<string, unknown>[] = [];
125+
const stream = toJsonLinesStream(jsonArray);
126+
const chunks: string[] = [];
127+
128+
for await (const chunk of stream) {
129+
chunks.push(chunk.toString());
130+
}
131+
132+
expect(chunks.join('')).toBe('');
133+
});
134+
135+
it('should throw an error if the input is not an array', () => {
136+
expect(() => toJsonLinesStream(null as unknown as Record<string, unknown>[])).toThrow(
137+
'Input must be an array of JSON objects.'
138+
);
139+
});
140+
});

0 commit comments

Comments
 (0)