csv-stream-lite 1.0.3 → 1.0.4
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/dist/parser.d.ts +6 -0
- package/dist/parser.js +41 -11
- package/package.json +1 -1
package/dist/parser.d.ts
CHANGED
|
@@ -9,8 +9,12 @@ export interface CsvEntityOptions {
|
|
|
9
9
|
separator?: string;
|
|
10
10
|
/** Character used to escape special characters. Defaults to '"' */
|
|
11
11
|
escapeChar?: string;
|
|
12
|
+
/** Character used to quote fields. Defaults to escapeChar value */
|
|
13
|
+
quoteChar?: string;
|
|
12
14
|
/** String used to denote new lines. Defaults to auto-detected '\r', '\n', or '\r\n' */
|
|
13
15
|
newline?: string;
|
|
16
|
+
/** Whether to trim whitespace from fields. Defaults to false. NOTE: this option is not supported when streaming, as trimming requires buffering the entire field. */
|
|
17
|
+
trim?: boolean;
|
|
14
18
|
}
|
|
15
19
|
/**
|
|
16
20
|
* Abstract base class for CSV entities that supports both synchronous and asynchronous parsing.
|
|
@@ -23,7 +27,9 @@ export declare abstract class CsvEntity<T, S = T> {
|
|
|
23
27
|
byteBuffer: ByteBuffer;
|
|
24
28
|
separator: string;
|
|
25
29
|
escapeChar: string;
|
|
30
|
+
quoteChar: string;
|
|
26
31
|
newline?: string;
|
|
32
|
+
trim: boolean;
|
|
27
33
|
consumed: boolean;
|
|
28
34
|
/**
|
|
29
35
|
* Creates a new CSV entity.
|
package/dist/parser.js
CHANGED
|
@@ -31,7 +31,9 @@ export class CsvEntity {
|
|
|
31
31
|
byteBuffer;
|
|
32
32
|
separator = ',';
|
|
33
33
|
escapeChar = '"';
|
|
34
|
+
quoteChar = '"';
|
|
34
35
|
newline;
|
|
36
|
+
trim = false;
|
|
35
37
|
consumed = false;
|
|
36
38
|
/**
|
|
37
39
|
* Creates a new CSV entity.
|
|
@@ -50,6 +52,16 @@ export class CsvEntity {
|
|
|
50
52
|
if (options?.escapeChar) {
|
|
51
53
|
this.escapeChar = options.escapeChar;
|
|
52
54
|
}
|
|
55
|
+
if (options?.quoteChar) {
|
|
56
|
+
this.quoteChar = options.quoteChar;
|
|
57
|
+
}
|
|
58
|
+
else if (options?.escapeChar) {
|
|
59
|
+
// Default quoteChar to escapeChar if only escapeChar is specified
|
|
60
|
+
this.quoteChar = options.escapeChar;
|
|
61
|
+
}
|
|
62
|
+
if (options?.trim !== undefined) {
|
|
63
|
+
this.trim = options.trim;
|
|
64
|
+
}
|
|
53
65
|
if (options?.newline !== undefined) {
|
|
54
66
|
const newline = options.newline;
|
|
55
67
|
if (newline === '') {
|
|
@@ -61,6 +73,9 @@ export class CsvEntity {
|
|
|
61
73
|
if (newline.includes(this.escapeChar)) {
|
|
62
74
|
throw new Error('Invalid CSV newline: newline option must not contain the escape character.');
|
|
63
75
|
}
|
|
76
|
+
if (newline.includes(this.quoteChar)) {
|
|
77
|
+
throw new Error('Invalid CSV newline: newline option must not contain the quote character.');
|
|
78
|
+
}
|
|
64
79
|
this.newline = newline;
|
|
65
80
|
}
|
|
66
81
|
}
|
|
@@ -230,14 +245,14 @@ export class CsvCell extends CsvEntity {
|
|
|
230
245
|
for (const part of this) {
|
|
231
246
|
str += part;
|
|
232
247
|
}
|
|
233
|
-
return str;
|
|
248
|
+
return this.trim ? str.trim() : str;
|
|
234
249
|
}
|
|
235
250
|
async parseAsync() {
|
|
236
251
|
let str = '';
|
|
237
252
|
for await (const part of this) {
|
|
238
253
|
str += part;
|
|
239
254
|
}
|
|
240
|
-
return str;
|
|
255
|
+
return this.trim ? str.trim() : str;
|
|
241
256
|
}
|
|
242
257
|
/**
|
|
243
258
|
* Reads the cell value and transforms it using the provided function.
|
|
@@ -272,22 +287,23 @@ export class CsvCell extends CsvEntity {
|
|
|
272
287
|
*streamImpl() {
|
|
273
288
|
const separator = this.separator.charCodeAt(0);
|
|
274
289
|
const escapeChar = this.escapeChar.charCodeAt(0);
|
|
290
|
+
const quoteChar = this.quoteChar.charCodeAt(0);
|
|
275
291
|
let chunk = [];
|
|
276
292
|
let hadData = false;
|
|
277
|
-
let
|
|
293
|
+
let isQuoted = false;
|
|
278
294
|
const next = this.byteBuffer.peek();
|
|
279
295
|
if (next === null && this.byteBuffer.eof) {
|
|
280
296
|
throw new Error('No more data to read');
|
|
281
297
|
}
|
|
282
|
-
if (next ===
|
|
283
|
-
|
|
284
|
-
this.byteBuffer.expect(
|
|
298
|
+
if (next === quoteChar) {
|
|
299
|
+
isQuoted = true;
|
|
300
|
+
this.byteBuffer.expect(quoteChar); // consume opening quote
|
|
285
301
|
}
|
|
286
302
|
while (this.byteBuffer.peek() !== null) {
|
|
287
303
|
const next = this.byteBuffer.peek();
|
|
288
|
-
if (
|
|
289
|
-
if (next === escapeChar) {
|
|
290
|
-
//
|
|
304
|
+
if (isQuoted) {
|
|
305
|
+
if (next === escapeChar && escapeChar === quoteChar) {
|
|
306
|
+
// Standard CSV: quote char doubles as escape char
|
|
291
307
|
const lookahead = this.byteBuffer.peek(1);
|
|
292
308
|
if (lookahead === escapeChar) {
|
|
293
309
|
// Escaped quote
|
|
@@ -301,6 +317,20 @@ export class CsvCell extends CsvEntity {
|
|
|
301
317
|
break;
|
|
302
318
|
}
|
|
303
319
|
}
|
|
320
|
+
else if (next === quoteChar) {
|
|
321
|
+
// End of quoted cell when using separate quote/escape chars
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
else if (next === escapeChar) {
|
|
325
|
+
// Handle escape character when different from quote char
|
|
326
|
+
const lookahead = this.byteBuffer.peek(1);
|
|
327
|
+
if (lookahead !== null) {
|
|
328
|
+
this.byteBuffer.expect(escapeChar); // consume escape char
|
|
329
|
+
const escapedChar = this.byteBuffer.next(); // consume escaped char
|
|
330
|
+
chunk.push(escapedChar);
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
304
334
|
}
|
|
305
335
|
else {
|
|
306
336
|
if (next === separator || this.isAtLineEnd()) {
|
|
@@ -315,8 +345,8 @@ export class CsvCell extends CsvEntity {
|
|
|
315
345
|
hadData = true;
|
|
316
346
|
}
|
|
317
347
|
}
|
|
318
|
-
if (
|
|
319
|
-
this.byteBuffer.expect(
|
|
348
|
+
if (isQuoted) {
|
|
349
|
+
this.byteBuffer.expect(quoteChar); // consume closing quote
|
|
320
350
|
}
|
|
321
351
|
if (this.byteBuffer.peek() === separator) {
|
|
322
352
|
this.byteBuffer.expect(separator); // consume separator
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "csv-stream-lite",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "A lightweight, memory-efficient, zero-dependency streaming CSV parser and stringifier for JavaScript and TypeScript. It works in both Node.js and browser environments.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|