convert-buddy-js 0.9.2 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -5
- package/dist/src/browser.d.ts +74 -0
- package/dist/src/browser.js +140 -0
- package/dist/src/browser.js.map +1 -0
- package/dist/src/index.d.ts +23 -2
- package/dist/src/index.js +82 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/node.d.ts +83 -2
- package/dist/src/node.js +270 -2
- package/dist/src/node.js.map +1 -1
- package/dist/tests/edge-cases/control-features.test.d.ts +2 -0
- package/dist/tests/edge-cases/control-features.test.js +87 -0
- package/dist/tests/edge-cases/control-features.test.js.map +1 -0
- package/dist/tests/edge-cases/csv-edge-cases.test.d.ts +2 -0
- package/dist/tests/edge-cases/csv-edge-cases.test.js +547 -0
- package/dist/tests/edge-cases/csv-edge-cases.test.js.map +1 -0
- package/dist/tests/edge-cases/detection.test.d.ts +2 -0
- package/dist/tests/edge-cases/detection.test.js +129 -0
- package/dist/tests/edge-cases/detection.test.js.map +1 -0
- package/dist/tests/edge-cases/error-handling.test.d.ts +2 -0
- package/dist/tests/edge-cases/error-handling.test.js +448 -0
- package/dist/tests/edge-cases/error-handling.test.js.map +1 -0
- package/dist/tests/edge-cases/ndjson-edge-cases.test.d.ts +2 -0
- package/dist/tests/edge-cases/ndjson-edge-cases.test.js +539 -0
- package/dist/tests/edge-cases/ndjson-edge-cases.test.js.map +1 -0
- package/dist/tests/edge-cases/node-helpers.test.d.ts +2 -0
- package/dist/tests/edge-cases/node-helpers.test.js +114 -0
- package/dist/tests/edge-cases/node-helpers.test.js.map +1 -0
- package/dist/wasm/nodejs/convert_buddy_bg.wasm +0 -0
- package/dist/wasm/web/convert_buddy_bg.wasm +0 -0
- package/package.json +6 -2
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import { convertToString, convert } from "../../src/index.js";
|
|
3
|
+
import { strict as assert } from "node:assert";
|
|
4
|
+
describe("NDJSON Edge Cases - Comprehensive Safety Tests", () => {
|
|
5
|
+
describe("Line Handling", () => {
|
|
6
|
+
it("should handle empty file", async () => {
|
|
7
|
+
const result = await convertToString("", {
|
|
8
|
+
inputFormat: "ndjson",
|
|
9
|
+
outputFormat: "json"
|
|
10
|
+
});
|
|
11
|
+
assert.strictEqual(result.trim(), "[]");
|
|
12
|
+
});
|
|
13
|
+
it("should handle file with only empty lines", async () => {
|
|
14
|
+
const ndjson = "\n\n\n\n";
|
|
15
|
+
const result = await convertToString(ndjson, {
|
|
16
|
+
inputFormat: "ndjson",
|
|
17
|
+
outputFormat: "json"
|
|
18
|
+
});
|
|
19
|
+
assert.strictEqual(result.trim(), "[]");
|
|
20
|
+
});
|
|
21
|
+
it("should handle lines with only whitespace", async () => {
|
|
22
|
+
const ndjson = " \n \n \n";
|
|
23
|
+
const result = await convertToString(ndjson, {
|
|
24
|
+
inputFormat: "ndjson",
|
|
25
|
+
outputFormat: "json"
|
|
26
|
+
});
|
|
27
|
+
assert.strictEqual(result.trim(), "[]");
|
|
28
|
+
});
|
|
29
|
+
it("should handle empty lines between records", async () => {
|
|
30
|
+
const ndjson = `{"name":"Alice"}
|
|
31
|
+
|
|
32
|
+
{"name":"Bob"}
|
|
33
|
+
|
|
34
|
+
{"name":"Charlie"}`;
|
|
35
|
+
const result = await convertToString(ndjson, {
|
|
36
|
+
inputFormat: "ndjson",
|
|
37
|
+
outputFormat: "json"
|
|
38
|
+
});
|
|
39
|
+
const parsed = JSON.parse(result);
|
|
40
|
+
assert.strictEqual(parsed.length, 3);
|
|
41
|
+
});
|
|
42
|
+
it("should handle very long lines (>10MB)", async () => {
|
|
43
|
+
const largeObj = { data: "A".repeat(1e6) };
|
|
44
|
+
const ndjson = JSON.stringify(largeObj);
|
|
45
|
+
const result = await convertToString(ndjson, {
|
|
46
|
+
inputFormat: "ndjson",
|
|
47
|
+
outputFormat: "json"
|
|
48
|
+
});
|
|
49
|
+
const parsed = JSON.parse(result);
|
|
50
|
+
assert.strictEqual(parsed.length, 1);
|
|
51
|
+
});
|
|
52
|
+
it("should handle missing trailing newline", async () => {
|
|
53
|
+
const ndjson = `{"name":"Alice"}
|
|
54
|
+
{"name":"Bob"}`;
|
|
55
|
+
const result = await convertToString(ndjson, {
|
|
56
|
+
inputFormat: "ndjson",
|
|
57
|
+
outputFormat: "json"
|
|
58
|
+
});
|
|
59
|
+
const parsed = JSON.parse(result);
|
|
60
|
+
assert.strictEqual(parsed.length, 2);
|
|
61
|
+
});
|
|
62
|
+
it("should handle multiple consecutive newlines", async () => {
|
|
63
|
+
const ndjson = `{"name":"Alice"}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
{"name":"Bob"}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
`;
|
|
70
|
+
const result = await convertToString(ndjson, {
|
|
71
|
+
inputFormat: "ndjson",
|
|
72
|
+
outputFormat: "json"
|
|
73
|
+
});
|
|
74
|
+
const parsed = JSON.parse(result);
|
|
75
|
+
assert.strictEqual(parsed.length, 2);
|
|
76
|
+
});
|
|
77
|
+
it("should handle single line NDJSON", async () => {
|
|
78
|
+
const ndjson = `{"name":"Alice"}`;
|
|
79
|
+
const result = await convertToString(ndjson, {
|
|
80
|
+
inputFormat: "ndjson",
|
|
81
|
+
outputFormat: "json"
|
|
82
|
+
});
|
|
83
|
+
const parsed = JSON.parse(result);
|
|
84
|
+
assert.strictEqual(parsed.length, 1);
|
|
85
|
+
});
|
|
86
|
+
it("should handle CRLF line endings", async () => {
|
|
87
|
+
const ndjson = `{"name":"Alice"}\r
|
|
88
|
+
{"name":"Bob"}\r
|
|
89
|
+
`;
|
|
90
|
+
const result = await convertToString(ndjson, {
|
|
91
|
+
inputFormat: "ndjson",
|
|
92
|
+
outputFormat: "json"
|
|
93
|
+
});
|
|
94
|
+
const parsed = JSON.parse(result);
|
|
95
|
+
assert.strictEqual(parsed.length, 2);
|
|
96
|
+
});
|
|
97
|
+
it("should handle mixed line endings (LF and CRLF)", async () => {
|
|
98
|
+
const ndjson = `{"name":"Alice"}
|
|
99
|
+
{"name":"Bob"}\r
|
|
100
|
+
{"name":"Charlie"}
|
|
101
|
+
`;
|
|
102
|
+
const result = await convertToString(ndjson, {
|
|
103
|
+
inputFormat: "ndjson",
|
|
104
|
+
outputFormat: "json"
|
|
105
|
+
});
|
|
106
|
+
const parsed = JSON.parse(result);
|
|
107
|
+
assert.strictEqual(parsed.length, 3);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe("JSON Validity", () => {
|
|
111
|
+
it("should handle valid JSON objects", async () => {
|
|
112
|
+
const ndjson = `{"name":"Alice","age":30}
|
|
113
|
+
{"name":"Bob","age":25}`;
|
|
114
|
+
const result = await convertToString(ndjson, {
|
|
115
|
+
inputFormat: "ndjson",
|
|
116
|
+
outputFormat: "json"
|
|
117
|
+
});
|
|
118
|
+
const parsed = JSON.parse(result);
|
|
119
|
+
assert.strictEqual(parsed.length, 2);
|
|
120
|
+
});
|
|
121
|
+
it("should handle JSON arrays as records", async () => {
|
|
122
|
+
const ndjson = `[1,2,3]
|
|
123
|
+
[4,5,6]
|
|
124
|
+
[7,8,9]`;
|
|
125
|
+
const result = await convertToString(ndjson, {
|
|
126
|
+
inputFormat: "ndjson",
|
|
127
|
+
outputFormat: "json"
|
|
128
|
+
});
|
|
129
|
+
const parsed = JSON.parse(result);
|
|
130
|
+
assert.strictEqual(parsed.length, 3);
|
|
131
|
+
});
|
|
132
|
+
it("should handle JSON primitives (strings)", async () => {
|
|
133
|
+
const ndjson = `"Alice"
|
|
134
|
+
"Bob"
|
|
135
|
+
"Charlie"`;
|
|
136
|
+
const result = await convertToString(ndjson, {
|
|
137
|
+
inputFormat: "ndjson",
|
|
138
|
+
outputFormat: "json"
|
|
139
|
+
});
|
|
140
|
+
const parsed = JSON.parse(result);
|
|
141
|
+
assert.strictEqual(parsed.length, 3);
|
|
142
|
+
});
|
|
143
|
+
it("should handle JSON primitives (numbers)", async () => {
|
|
144
|
+
const ndjson = `42
|
|
145
|
+
3.14
|
|
146
|
+
-100`;
|
|
147
|
+
const result = await convertToString(ndjson, {
|
|
148
|
+
inputFormat: "ndjson",
|
|
149
|
+
outputFormat: "json"
|
|
150
|
+
});
|
|
151
|
+
const parsed = JSON.parse(result);
|
|
152
|
+
assert.strictEqual(parsed.length, 3);
|
|
153
|
+
});
|
|
154
|
+
it("should handle JSON primitives (booleans)", async () => {
|
|
155
|
+
const ndjson = `true
|
|
156
|
+
false
|
|
157
|
+
true`;
|
|
158
|
+
const result = await convertToString(ndjson, {
|
|
159
|
+
inputFormat: "ndjson",
|
|
160
|
+
outputFormat: "json"
|
|
161
|
+
});
|
|
162
|
+
const parsed = JSON.parse(result);
|
|
163
|
+
assert.strictEqual(parsed.length, 3);
|
|
164
|
+
});
|
|
165
|
+
it("should handle JSON null values", async () => {
|
|
166
|
+
const ndjson = `null
|
|
167
|
+
null
|
|
168
|
+
null`;
|
|
169
|
+
const result = await convertToString(ndjson, {
|
|
170
|
+
inputFormat: "ndjson",
|
|
171
|
+
outputFormat: "json"
|
|
172
|
+
});
|
|
173
|
+
const parsed = JSON.parse(result);
|
|
174
|
+
assert.strictEqual(parsed.length, 3);
|
|
175
|
+
});
|
|
176
|
+
it("should handle deeply nested objects (>10 levels)", async () => {
|
|
177
|
+
let obj = { value: "deep" };
|
|
178
|
+
for (let i = 0; i < 15; i++) {
|
|
179
|
+
obj = { nested: obj };
|
|
180
|
+
}
|
|
181
|
+
const ndjson = JSON.stringify(obj);
|
|
182
|
+
const result = await convertToString(ndjson, {
|
|
183
|
+
inputFormat: "ndjson",
|
|
184
|
+
outputFormat: "json"
|
|
185
|
+
});
|
|
186
|
+
const parsed = JSON.parse(result);
|
|
187
|
+
assert.strictEqual(parsed.length, 1);
|
|
188
|
+
});
|
|
189
|
+
it("should handle large arrays (>1000 elements)", async () => {
|
|
190
|
+
const largeArray = Array.from({ length: 2e3 }, (_, i) => i);
|
|
191
|
+
const ndjson = JSON.stringify(largeArray);
|
|
192
|
+
const result = await convertToString(ndjson, {
|
|
193
|
+
inputFormat: "ndjson",
|
|
194
|
+
outputFormat: "json"
|
|
195
|
+
});
|
|
196
|
+
const parsed = JSON.parse(result);
|
|
197
|
+
assert.strictEqual(parsed.length, 1);
|
|
198
|
+
});
|
|
199
|
+
it("should handle Unicode escape sequences", async () => {
|
|
200
|
+
const ndjson = `{"emoji":"\\u{1F600}"}
|
|
201
|
+
{"text":"\\u0048\\u0065\\u006C\\u006C\\u006F"}`;
|
|
202
|
+
const result = await convertToString(ndjson, {
|
|
203
|
+
inputFormat: "ndjson",
|
|
204
|
+
outputFormat: "json"
|
|
205
|
+
});
|
|
206
|
+
const parsed = JSON.parse(result);
|
|
207
|
+
assert.strictEqual(parsed.length, 2);
|
|
208
|
+
});
|
|
209
|
+
it("should handle special characters in strings", async () => {
|
|
210
|
+
const ndjson = `{"text":"Line 1\\nLine 2"}
|
|
211
|
+
{"text":"Tab\\there"}`;
|
|
212
|
+
const result = await convertToString(ndjson, {
|
|
213
|
+
inputFormat: "ndjson",
|
|
214
|
+
outputFormat: "json"
|
|
215
|
+
});
|
|
216
|
+
const parsed = JSON.parse(result);
|
|
217
|
+
assert.strictEqual(parsed.length, 2);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
describe("Data Types", () => {
|
|
221
|
+
it("should handle all JSON types in single record", async () => {
|
|
222
|
+
const ndjson = `{"string":"text","number":42,"boolean":true,"null":null,"array":[1,2,3],"object":{"nested":"value"}}`;
|
|
223
|
+
const result = await convertToString(ndjson, {
|
|
224
|
+
inputFormat: "ndjson",
|
|
225
|
+
outputFormat: "json"
|
|
226
|
+
});
|
|
227
|
+
const parsed = JSON.parse(result);
|
|
228
|
+
assert.strictEqual(parsed.length, 1);
|
|
229
|
+
assert.strictEqual(parsed[0].string, "text");
|
|
230
|
+
assert.strictEqual(parsed[0].number, 42);
|
|
231
|
+
assert.strictEqual(parsed[0].boolean, true);
|
|
232
|
+
assert.strictEqual(parsed[0].null, null);
|
|
233
|
+
});
|
|
234
|
+
it("should handle mixed types across records", async () => {
|
|
235
|
+
const ndjson = `{"type":"object"}
|
|
236
|
+
[1,2,3]
|
|
237
|
+
"string"
|
|
238
|
+
42
|
|
239
|
+
true
|
|
240
|
+
null`;
|
|
241
|
+
const result = await convertToString(ndjson, {
|
|
242
|
+
inputFormat: "ndjson",
|
|
243
|
+
outputFormat: "json"
|
|
244
|
+
});
|
|
245
|
+
const parsed = JSON.parse(result);
|
|
246
|
+
assert.strictEqual(parsed.length, 6);
|
|
247
|
+
});
|
|
248
|
+
it("should handle empty objects", async () => {
|
|
249
|
+
const ndjson = `{}
|
|
250
|
+
{}
|
|
251
|
+
{}`;
|
|
252
|
+
const result = await convertToString(ndjson, {
|
|
253
|
+
inputFormat: "ndjson",
|
|
254
|
+
outputFormat: "json"
|
|
255
|
+
});
|
|
256
|
+
const parsed = JSON.parse(result);
|
|
257
|
+
assert.strictEqual(parsed.length, 3);
|
|
258
|
+
});
|
|
259
|
+
it("should handle empty arrays", async () => {
|
|
260
|
+
const ndjson = `[]
|
|
261
|
+
[]
|
|
262
|
+
[]`;
|
|
263
|
+
const result = await convertToString(ndjson, {
|
|
264
|
+
inputFormat: "ndjson",
|
|
265
|
+
outputFormat: "json"
|
|
266
|
+
});
|
|
267
|
+
const parsed = JSON.parse(result);
|
|
268
|
+
assert.strictEqual(parsed.length, 3);
|
|
269
|
+
});
|
|
270
|
+
it("should handle very large strings (>1MB)", async () => {
|
|
271
|
+
const largeString = "A".repeat(2e6);
|
|
272
|
+
const ndjson = JSON.stringify({ data: largeString });
|
|
273
|
+
const result = await convertToString(ndjson, {
|
|
274
|
+
inputFormat: "ndjson",
|
|
275
|
+
outputFormat: "json"
|
|
276
|
+
});
|
|
277
|
+
const parsed = JSON.parse(result);
|
|
278
|
+
assert.strictEqual(parsed.length, 1);
|
|
279
|
+
});
|
|
280
|
+
it("should handle numbers at precision limits", async () => {
|
|
281
|
+
const ndjson = `{"max":${Number.MAX_SAFE_INTEGER}}
|
|
282
|
+
{"min":${Number.MIN_SAFE_INTEGER}}
|
|
283
|
+
{"float":${Number.MAX_VALUE}}`;
|
|
284
|
+
const result = await convertToString(ndjson, {
|
|
285
|
+
inputFormat: "ndjson",
|
|
286
|
+
outputFormat: "json"
|
|
287
|
+
});
|
|
288
|
+
const parsed = JSON.parse(result);
|
|
289
|
+
assert.strictEqual(parsed.length, 3);
|
|
290
|
+
});
|
|
291
|
+
it("should handle objects with many keys (>1000)", async () => {
|
|
292
|
+
const obj = {};
|
|
293
|
+
for (let i = 0; i < 1500; i++) {
|
|
294
|
+
obj[`key${i}`] = i;
|
|
295
|
+
}
|
|
296
|
+
const ndjson = JSON.stringify(obj);
|
|
297
|
+
const result = await convertToString(ndjson, {
|
|
298
|
+
inputFormat: "ndjson",
|
|
299
|
+
outputFormat: "json"
|
|
300
|
+
});
|
|
301
|
+
const parsed = JSON.parse(result);
|
|
302
|
+
assert.strictEqual(parsed.length, 1);
|
|
303
|
+
assert.strictEqual(Object.keys(parsed[0]).length, 1500);
|
|
304
|
+
});
|
|
305
|
+
it("should handle objects with duplicate keys (last wins)", async () => {
|
|
306
|
+
const ndjson = `{"key":"value1","key":"value2"}`;
|
|
307
|
+
const result = await convertToString(ndjson, {
|
|
308
|
+
inputFormat: "ndjson",
|
|
309
|
+
outputFormat: "json"
|
|
310
|
+
});
|
|
311
|
+
const parsed = JSON.parse(result);
|
|
312
|
+
assert.strictEqual(parsed.length, 1);
|
|
313
|
+
});
|
|
314
|
+
it("should handle objects with special key names", async () => {
|
|
315
|
+
const ndjson = `{"":"empty","123":"numeric","@#$":"special","__proto__":"proto"}`;
|
|
316
|
+
const result = await convertToString(ndjson, {
|
|
317
|
+
inputFormat: "ndjson",
|
|
318
|
+
outputFormat: "json"
|
|
319
|
+
});
|
|
320
|
+
const parsed = JSON.parse(result);
|
|
321
|
+
assert.strictEqual(parsed.length, 1);
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
describe("NDJSON Passthrough", () => {
|
|
325
|
+
it("should handle NDJSON \u2192 NDJSON passthrough", async () => {
|
|
326
|
+
const ndjson = `{"name":"Alice"}
|
|
327
|
+
{"name":"Bob"}
|
|
328
|
+
{"name":"Charlie"}`;
|
|
329
|
+
const result = await convertToString(ndjson, {
|
|
330
|
+
inputFormat: "ndjson",
|
|
331
|
+
outputFormat: "ndjson"
|
|
332
|
+
});
|
|
333
|
+
const lines = result.trim().split("\n");
|
|
334
|
+
assert.strictEqual(lines.length, 3);
|
|
335
|
+
});
|
|
336
|
+
it("should preserve record order in passthrough", async () => {
|
|
337
|
+
const ndjson = `{"id":1}
|
|
338
|
+
{"id":2}
|
|
339
|
+
{"id":3}`;
|
|
340
|
+
const result = await convertToString(ndjson, {
|
|
341
|
+
inputFormat: "ndjson",
|
|
342
|
+
outputFormat: "ndjson"
|
|
343
|
+
});
|
|
344
|
+
const lines = result.trim().split("\n");
|
|
345
|
+
const first = JSON.parse(lines[0]);
|
|
346
|
+
assert.strictEqual(first.id, 1);
|
|
347
|
+
});
|
|
348
|
+
it("should handle large passthrough (10K records)", async () => {
|
|
349
|
+
let ndjson = "";
|
|
350
|
+
for (let i = 0; i < 1e4; i++) {
|
|
351
|
+
ndjson += `{"id":${i}}
|
|
352
|
+
`;
|
|
353
|
+
}
|
|
354
|
+
const result = await convertToString(ndjson, {
|
|
355
|
+
inputFormat: "ndjson",
|
|
356
|
+
outputFormat: "ndjson"
|
|
357
|
+
});
|
|
358
|
+
const lines = result.trim().split("\n");
|
|
359
|
+
assert.strictEqual(lines.length, 1e4);
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
describe("Streaming and Chunk Boundaries", () => {
|
|
363
|
+
it("should handle records split across chunks", async () => {
|
|
364
|
+
const ndjson = `{"name":"Alice"}
|
|
365
|
+
{"name":"Bob"}
|
|
366
|
+
{"name":"Charlie"}`;
|
|
367
|
+
const data = new TextEncoder().encode(ndjson);
|
|
368
|
+
const result = await convert(data, {
|
|
369
|
+
inputFormat: "ndjson",
|
|
370
|
+
outputFormat: "json"
|
|
371
|
+
});
|
|
372
|
+
const resultStr = new TextDecoder().decode(result);
|
|
373
|
+
const parsed = JSON.parse(resultStr);
|
|
374
|
+
assert.strictEqual(parsed.length, 3);
|
|
375
|
+
});
|
|
376
|
+
it("should handle partial JSON objects across chunks", async () => {
|
|
377
|
+
const ndjson = `{"name":"Alice","age":30}
|
|
378
|
+
{"name":"Bob","age":25}`;
|
|
379
|
+
const result = await convertToString(ndjson, {
|
|
380
|
+
inputFormat: "ndjson",
|
|
381
|
+
outputFormat: "json"
|
|
382
|
+
});
|
|
383
|
+
const parsed = JSON.parse(result);
|
|
384
|
+
assert.strictEqual(parsed.length, 2);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
describe("Performance Edge Cases", () => {
|
|
388
|
+
it("should handle tiny files (<100 bytes)", async () => {
|
|
389
|
+
const ndjson = `{"a":1}`;
|
|
390
|
+
const result = await convertToString(ndjson, {
|
|
391
|
+
inputFormat: "ndjson",
|
|
392
|
+
outputFormat: "json"
|
|
393
|
+
});
|
|
394
|
+
assert.ok(result.length > 0);
|
|
395
|
+
});
|
|
396
|
+
it("should handle many small records", async () => {
|
|
397
|
+
let ndjson = "";
|
|
398
|
+
for (let i = 0; i < 1e3; i++) {
|
|
399
|
+
ndjson += `{"id":${i}}
|
|
400
|
+
`;
|
|
401
|
+
}
|
|
402
|
+
const result = await convertToString(ndjson, {
|
|
403
|
+
inputFormat: "ndjson",
|
|
404
|
+
outputFormat: "json"
|
|
405
|
+
});
|
|
406
|
+
const parsed = JSON.parse(result);
|
|
407
|
+
assert.strictEqual(parsed.length, 1e3);
|
|
408
|
+
});
|
|
409
|
+
it("should handle few large records", async () => {
|
|
410
|
+
const largeValue = "A".repeat(5e4);
|
|
411
|
+
const ndjson = `{"data":"${largeValue}"}
|
|
412
|
+
{"data":"${largeValue}"}`;
|
|
413
|
+
const result = await convertToString(ndjson, {
|
|
414
|
+
inputFormat: "ndjson",
|
|
415
|
+
outputFormat: "json"
|
|
416
|
+
});
|
|
417
|
+
const parsed = JSON.parse(result);
|
|
418
|
+
assert.strictEqual(parsed.length, 2);
|
|
419
|
+
});
|
|
420
|
+
it("should handle highly compressible data", async () => {
|
|
421
|
+
let ndjson = "";
|
|
422
|
+
for (let i = 0; i < 100; i++) {
|
|
423
|
+
ndjson += `{"name":"Alice","value":100}
|
|
424
|
+
`;
|
|
425
|
+
}
|
|
426
|
+
const result = await convertToString(ndjson, {
|
|
427
|
+
inputFormat: "ndjson",
|
|
428
|
+
outputFormat: "json"
|
|
429
|
+
});
|
|
430
|
+
const parsed = JSON.parse(result);
|
|
431
|
+
assert.strictEqual(parsed.length, 100);
|
|
432
|
+
});
|
|
433
|
+
it("should handle random data (low compressibility)", async () => {
|
|
434
|
+
let ndjson = "";
|
|
435
|
+
for (let i = 0; i < 100; i++) {
|
|
436
|
+
ndjson += `{"id":"${Math.random().toString(36)}","value":${Math.random()}}
|
|
437
|
+
`;
|
|
438
|
+
}
|
|
439
|
+
const result = await convertToString(ndjson, {
|
|
440
|
+
inputFormat: "ndjson",
|
|
441
|
+
outputFormat: "json"
|
|
442
|
+
});
|
|
443
|
+
const parsed = JSON.parse(result);
|
|
444
|
+
assert.strictEqual(parsed.length, 100);
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
describe("Malformed Input Handling", () => {
|
|
448
|
+
it("should handle invalid JSON syntax gracefully", async () => {
|
|
449
|
+
const ndjson = `{"name":"Alice"}
|
|
450
|
+
{invalid json}
|
|
451
|
+
{"name":"Bob"}`;
|
|
452
|
+
try {
|
|
453
|
+
const result = await convertToString(ndjson, {
|
|
454
|
+
inputFormat: "ndjson",
|
|
455
|
+
outputFormat: "json"
|
|
456
|
+
});
|
|
457
|
+
assert.ok(true);
|
|
458
|
+
} catch (error) {
|
|
459
|
+
assert.ok(error);
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
it("should handle incomplete JSON objects", async () => {
|
|
463
|
+
const ndjson = `{"name":"Alice"
|
|
464
|
+
{"name":"Bob"}`;
|
|
465
|
+
try {
|
|
466
|
+
const result = await convertToString(ndjson, {
|
|
467
|
+
inputFormat: "ndjson",
|
|
468
|
+
outputFormat: "json"
|
|
469
|
+
});
|
|
470
|
+
assert.ok(true);
|
|
471
|
+
} catch (error) {
|
|
472
|
+
assert.ok(error);
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
it("should handle truncated JSON", async () => {
|
|
476
|
+
const ndjson = `{"name":"Alice","age":30,"city":"N`;
|
|
477
|
+
try {
|
|
478
|
+
const result = await convertToString(ndjson, {
|
|
479
|
+
inputFormat: "ndjson",
|
|
480
|
+
outputFormat: "json"
|
|
481
|
+
});
|
|
482
|
+
assert.ok(true);
|
|
483
|
+
} catch (error) {
|
|
484
|
+
assert.ok(error);
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
it("should handle mixed valid and invalid lines", async () => {
|
|
488
|
+
const ndjson = `{"valid":1}
|
|
489
|
+
invalid
|
|
490
|
+
{"valid":2}
|
|
491
|
+
{broken
|
|
492
|
+
{"valid":3}`;
|
|
493
|
+
try {
|
|
494
|
+
const result = await convertToString(ndjson, {
|
|
495
|
+
inputFormat: "ndjson",
|
|
496
|
+
outputFormat: "json"
|
|
497
|
+
});
|
|
498
|
+
assert.ok(true);
|
|
499
|
+
} catch (error) {
|
|
500
|
+
assert.ok(error);
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
describe("Unicode and Encoding", () => {
|
|
505
|
+
it("should handle Unicode characters", async () => {
|
|
506
|
+
const ndjson = `{"emoji":"\u{1F600}\u{1F389}\u{1F680}"}
|
|
507
|
+
{"text":"\u65E5\u672C\u8A9E"}
|
|
508
|
+
{"symbols":"\u03B1\u03B2\u03B3\u03B4"}`;
|
|
509
|
+
const result = await convertToString(ndjson, {
|
|
510
|
+
inputFormat: "ndjson",
|
|
511
|
+
outputFormat: "json"
|
|
512
|
+
});
|
|
513
|
+
const parsed = JSON.parse(result);
|
|
514
|
+
assert.strictEqual(parsed.length, 3);
|
|
515
|
+
assert.ok(parsed[0].emoji.includes("\u{1F600}"));
|
|
516
|
+
});
|
|
517
|
+
it("should handle surrogate pairs", async () => {
|
|
518
|
+
const ndjson = `{"emoji":"\u{1D573}\u{1D58A}\u{1D591}\u{1D591}\u{1D594}"}`;
|
|
519
|
+
const result = await convertToString(ndjson, {
|
|
520
|
+
inputFormat: "ndjson",
|
|
521
|
+
outputFormat: "json"
|
|
522
|
+
});
|
|
523
|
+
const parsed = JSON.parse(result);
|
|
524
|
+
assert.strictEqual(parsed.length, 1);
|
|
525
|
+
});
|
|
526
|
+
it("should handle zero-width characters", async () => {
|
|
527
|
+
const ndjson = `{"text":"Hello\u200BWorld"}`;
|
|
528
|
+
const result = await convertToString(ndjson, {
|
|
529
|
+
inputFormat: "ndjson",
|
|
530
|
+
outputFormat: "json"
|
|
531
|
+
});
|
|
532
|
+
const parsed = JSON.parse(result);
|
|
533
|
+
assert.strictEqual(parsed.length, 1);
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
console.log("\u2713 NDJSON Edge Case Test Suite loaded");
|
|
538
|
+
console.log(" Run with: node --test tests/edge-cases/ndjson-edge-cases.test.ts");
|
|
539
|
+
//# sourceMappingURL=ndjson-edge-cases.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../tests/edge-cases/ndjson-edge-cases.test.ts"],"sourcesContent":["import { describe, it } from \"node:test\";\r\nimport { convertToString, convert } from \"../../src/index.js\";\r\nimport { strict as assert } from \"node:assert\";\r\n\r\n/**\r\n * Comprehensive NDJSON Edge Case Test Suite\r\n * \r\n * Tests all possible edge cases for NDJSON parsing to ensure maximum safety.\r\n */\r\n\r\ndescribe(\"NDJSON Edge Cases - Comprehensive Safety Tests\", () => {\r\n \r\n // ========== LINE HANDLING ==========\r\n describe(\"Line Handling\", () => {\r\n it(\"should handle empty file\", async () => {\r\n const result = await convertToString(\"\", {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n assert.strictEqual(result.trim(), \"[]\");\r\n });\r\n\r\n it(\"should handle file with only empty lines\", async () => {\r\n const ndjson = \"\\n\\n\\n\\n\";\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n assert.strictEqual(result.trim(), \"[]\");\r\n });\r\n\r\n it(\"should handle lines with only whitespace\", async () => {\r\n const ndjson = \" \\n \\n \\n\";\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n assert.strictEqual(result.trim(), \"[]\");\r\n });\r\n\r\n it(\"should handle empty lines between records\", async () => {\r\n const ndjson = `{\"name\":\"Alice\"}\\n\\n{\"name\":\"Bob\"}\\n\\n{\"name\":\"Charlie\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 3);\r\n });\r\n\r\n it(\"should handle very long lines (>10MB)\", async () => {\r\n const largeObj = { data: \"A\".repeat(1000000) };\r\n const ndjson = JSON.stringify(largeObj);\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1);\r\n });\r\n\r\n it(\"should handle missing trailing newline\", async () => {\r\n const ndjson = `{\"name\":\"Alice\"}\\n{\"name\":\"Bob\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 2);\r\n });\r\n\r\n it(\"should handle multiple consecutive newlines\", async () => {\r\n const ndjson = `{\"name\":\"Alice\"}\\n\\n\\n{\"name\":\"Bob\"}\\n\\n\\n`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 2);\r\n });\r\n\r\n it(\"should handle single line NDJSON\", async () => {\r\n const ndjson = `{\"name\":\"Alice\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1);\r\n });\r\n\r\n it(\"should handle CRLF line endings\", async () => {\r\n const ndjson = `{\"name\":\"Alice\"}\\r\\n{\"name\":\"Bob\"}\\r\\n`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 2);\r\n });\r\n\r\n it(\"should handle mixed line endings (LF and CRLF)\", async () => {\r\n const ndjson = `{\"name\":\"Alice\"}\\n{\"name\":\"Bob\"}\\r\\n{\"name\":\"Charlie\"}\\n`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 3);\r\n });\r\n });\r\n\r\n // ========== JSON VALIDITY ==========\r\n describe(\"JSON Validity\", () => {\r\n it(\"should handle valid JSON objects\", async () => {\r\n const ndjson = `{\"name\":\"Alice\",\"age\":30}\\n{\"name\":\"Bob\",\"age\":25}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 2);\r\n });\r\n\r\n it(\"should handle JSON arrays as records\", async () => {\r\n const ndjson = `[1,2,3]\\n[4,5,6]\\n[7,8,9]`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 3);\r\n });\r\n\r\n it(\"should handle JSON primitives (strings)\", async () => {\r\n const ndjson = `\"Alice\"\\n\"Bob\"\\n\"Charlie\"`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 3);\r\n });\r\n\r\n it(\"should handle JSON primitives (numbers)\", async () => {\r\n const ndjson = `42\\n3.14\\n-100`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 3);\r\n });\r\n\r\n it(\"should handle JSON primitives (booleans)\", async () => {\r\n const ndjson = `true\\nfalse\\ntrue`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 3);\r\n });\r\n\r\n it(\"should handle JSON null values\", async () => {\r\n const ndjson = `null\\nnull\\nnull`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 3);\r\n });\r\n\r\n it(\"should handle deeply nested objects (>10 levels)\", async () => {\r\n let obj: any = { value: \"deep\" };\r\n for (let i = 0; i < 15; i++) {\r\n obj = { nested: obj };\r\n }\r\n const ndjson = JSON.stringify(obj);\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1);\r\n });\r\n\r\n it(\"should handle large arrays (>1000 elements)\", async () => {\r\n const largeArray = Array.from({ length: 2000 }, (_, i) => i);\r\n const ndjson = JSON.stringify(largeArray);\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1);\r\n });\r\n\r\n it(\"should handle Unicode escape sequences\", async () => {\r\n const ndjson = `{\"emoji\":\"\\\\u{1F600}\"}\\n{\"text\":\"\\\\u0048\\\\u0065\\\\u006C\\\\u006C\\\\u006F\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 2);\r\n });\r\n\r\n it(\"should handle special characters in strings\", async () => {\r\n const ndjson = `{\"text\":\"Line 1\\\\nLine 2\"}\\n{\"text\":\"Tab\\\\there\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 2);\r\n });\r\n });\r\n\r\n // ========== DATA TYPES ==========\r\n describe(\"Data Types\", () => {\r\n it(\"should handle all JSON types in single record\", async () => {\r\n const ndjson = `{\"string\":\"text\",\"number\":42,\"boolean\":true,\"null\":null,\"array\":[1,2,3],\"object\":{\"nested\":\"value\"}}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1);\r\n assert.strictEqual(parsed[0].string, \"text\");\r\n assert.strictEqual(parsed[0].number, 42);\r\n assert.strictEqual(parsed[0].boolean, true);\r\n assert.strictEqual(parsed[0].null, null);\r\n });\r\n\r\n it(\"should handle mixed types across records\", async () => {\r\n const ndjson = `{\"type\":\"object\"}\\n[1,2,3]\\n\"string\"\\n42\\ntrue\\nnull`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 6);\r\n });\r\n\r\n it(\"should handle empty objects\", async () => {\r\n const ndjson = `{}\\n{}\\n{}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 3);\r\n });\r\n\r\n it(\"should handle empty arrays\", async () => {\r\n const ndjson = `[]\\n[]\\n[]`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 3);\r\n });\r\n\r\n it(\"should handle very large strings (>1MB)\", async () => {\r\n const largeString = \"A\".repeat(2000000);\r\n const ndjson = JSON.stringify({ data: largeString });\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1);\r\n });\r\n\r\n it(\"should handle numbers at precision limits\", async () => {\r\n const ndjson = `{\"max\":${Number.MAX_SAFE_INTEGER}}\\n{\"min\":${Number.MIN_SAFE_INTEGER}}\\n{\"float\":${Number.MAX_VALUE}}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 3);\r\n });\r\n\r\n it(\"should handle objects with many keys (>1000)\", async () => {\r\n const obj: any = {};\r\n for (let i = 0; i < 1500; i++) {\r\n obj[`key${i}`] = i;\r\n }\r\n const ndjson = JSON.stringify(obj);\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1);\r\n assert.strictEqual(Object.keys(parsed[0]).length, 1500);\r\n });\r\n\r\n it(\"should handle objects with duplicate keys (last wins)\", async () => {\r\n const ndjson = `{\"key\":\"value1\",\"key\":\"value2\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1);\r\n });\r\n\r\n it(\"should handle objects with special key names\", async () => {\r\n const ndjson = `{\"\":\"empty\",\"123\":\"numeric\",\"@#$\":\"special\",\"__proto__\":\"proto\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1);\r\n });\r\n });\r\n\r\n // ========== NDJSON PASSTHROUGH ==========\r\n describe(\"NDJSON Passthrough\", () => {\r\n it(\"should handle NDJSON → NDJSON passthrough\", async () => {\r\n const ndjson = `{\"name\":\"Alice\"}\\n{\"name\":\"Bob\"}\\n{\"name\":\"Charlie\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"ndjson\",\r\n });\r\n const lines = result.trim().split(\"\\n\");\r\n assert.strictEqual(lines.length, 3);\r\n });\r\n\r\n it(\"should preserve record order in passthrough\", async () => {\r\n const ndjson = `{\"id\":1}\\n{\"id\":2}\\n{\"id\":3}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"ndjson\",\r\n });\r\n const lines = result.trim().split(\"\\n\");\r\n const first = JSON.parse(lines[0]);\r\n assert.strictEqual(first.id, 1);\r\n });\r\n\r\n it(\"should handle large passthrough (10K records)\", async () => {\r\n let ndjson = \"\";\r\n for (let i = 0; i < 10000; i++) {\r\n ndjson += `{\"id\":${i}}\\n`;\r\n }\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"ndjson\",\r\n });\r\n const lines = result.trim().split(\"\\n\");\r\n assert.strictEqual(lines.length, 10000);\r\n });\r\n });\r\n\r\n // ========== STREAMING AND BOUNDARIES ==========\r\n describe(\"Streaming and Chunk Boundaries\", () => {\r\n it(\"should handle records split across chunks\", async () => {\r\n const ndjson = `{\"name\":\"Alice\"}\\n{\"name\":\"Bob\"}\\n{\"name\":\"Charlie\"}`;\r\n const data = new TextEncoder().encode(ndjson);\r\n \r\n const result = await convert(data, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n \r\n const resultStr = new TextDecoder().decode(result);\r\n const parsed = JSON.parse(resultStr);\r\n assert.strictEqual(parsed.length, 3);\r\n });\r\n\r\n it(\"should handle partial JSON objects across chunks\", async () => {\r\n const ndjson = `{\"name\":\"Alice\",\"age\":30}\\n{\"name\":\"Bob\",\"age\":25}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 2);\r\n });\r\n });\r\n\r\n // ========== PERFORMANCE EDGE CASES ==========\r\n describe(\"Performance Edge Cases\", () => {\r\n it(\"should handle tiny files (<100 bytes)\", async () => {\r\n const ndjson = `{\"a\":1}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n assert.ok(result.length > 0);\r\n });\r\n\r\n it(\"should handle many small records\", async () => {\r\n let ndjson = \"\";\r\n for (let i = 0; i < 1000; i++) {\r\n ndjson += `{\"id\":${i}}\\n`;\r\n }\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1000);\r\n });\r\n\r\n it(\"should handle few large records\", async () => {\r\n const largeValue = \"A\".repeat(50000);\r\n const ndjson = `{\"data\":\"${largeValue}\"}\\n{\"data\":\"${largeValue}\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 2);\r\n });\r\n\r\n it(\"should handle highly compressible data\", async () => {\r\n let ndjson = \"\";\r\n for (let i = 0; i < 100; i++) {\r\n ndjson += `{\"name\":\"Alice\",\"value\":100}\\n`;\r\n }\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 100);\r\n });\r\n\r\n it(\"should handle random data (low compressibility)\", async () => {\r\n let ndjson = \"\";\r\n for (let i = 0; i < 100; i++) {\r\n ndjson += `{\"id\":\"${Math.random().toString(36)}\",\"value\":${Math.random()}}\\n`;\r\n }\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 100);\r\n });\r\n });\r\n\r\n // ========== MALFORMED INPUT (ERROR HANDLING) ==========\r\n describe(\"Malformed Input Handling\", () => {\r\n it(\"should handle invalid JSON syntax gracefully\", async () => {\r\n const ndjson = `{\"name\":\"Alice\"}\\n{invalid json}\\n{\"name\":\"Bob\"}`;\r\n try {\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n // If it succeeds, it handled it gracefully (maybe skipped invalid line)\r\n assert.ok(true);\r\n } catch (error) {\r\n // If it fails, it detected the error\r\n assert.ok(error);\r\n }\r\n });\r\n\r\n it(\"should handle incomplete JSON objects\", async () => {\r\n const ndjson = `{\"name\":\"Alice\"\\n{\"name\":\"Bob\"}`;\r\n try {\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n assert.ok(true);\r\n } catch (error) {\r\n assert.ok(error);\r\n }\r\n });\r\n\r\n it(\"should handle truncated JSON\", async () => {\r\n const ndjson = `{\"name\":\"Alice\",\"age\":30,\"city\":\"N`;\r\n try {\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n assert.ok(true);\r\n } catch (error) {\r\n assert.ok(error);\r\n }\r\n });\r\n\r\n it(\"should handle mixed valid and invalid lines\", async () => {\r\n const ndjson = `{\"valid\":1}\\ninvalid\\n{\"valid\":2}\\n{broken\\n{\"valid\":3}`;\r\n try {\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n assert.ok(true);\r\n } catch (error) {\r\n assert.ok(error);\r\n }\r\n });\r\n });\r\n\r\n // ========== UNICODE AND ENCODING ==========\r\n describe(\"Unicode and Encoding\", () => {\r\n it(\"should handle Unicode characters\", async () => {\r\n const ndjson = `{\"emoji\":\"😀🎉🚀\"}\\n{\"text\":\"日本語\"}\\n{\"symbols\":\"αβγδ\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 3);\r\n assert.ok(parsed[0].emoji.includes(\"😀\"));\r\n });\r\n\r\n it(\"should handle surrogate pairs\", async () => {\r\n const ndjson = `{\"emoji\":\"𝕳𝖊𝖑𝖑𝖔\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1);\r\n });\r\n\r\n it(\"should handle zero-width characters\", async () => {\r\n const ndjson = `{\"text\":\"Hello\\u200BWorld\"}`;\r\n const result = await convertToString(ndjson, {\r\n inputFormat: \"ndjson\",\r\n outputFormat: \"json\",\r\n });\r\n const parsed = JSON.parse(result);\r\n assert.strictEqual(parsed.length, 1);\r\n });\r\n });\r\n});\r\n\r\nconsole.log(\"✓ NDJSON Edge Case Test Suite loaded\");\r\nconsole.log(\" Run with: node --test tests/edge-cases/ndjson-edge-cases.test.ts\");\r\n"],"mappings":"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","names":[]}
|