csv-stream-lite 1.0.2 → 1.0.3
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 +17 -1
- package/dist/parser.js +66 -4
- package/package.json +1 -1
package/dist/parser.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface CsvEntityOptions {
|
|
|
9
9
|
separator?: string;
|
|
10
10
|
/** Character used to escape special characters. Defaults to '"' */
|
|
11
11
|
escapeChar?: string;
|
|
12
|
+
/** String used to denote new lines. Defaults to auto-detected '\r', '\n', or '\r\n' */
|
|
13
|
+
newline?: string;
|
|
12
14
|
}
|
|
13
15
|
/**
|
|
14
16
|
* Abstract base class for CSV entities that supports both synchronous and asynchronous parsing.
|
|
@@ -17,10 +19,11 @@ export interface CsvEntityOptions {
|
|
|
17
19
|
* @typeParam T - The type returned by read operations
|
|
18
20
|
* @typeParam S - The type yielded by stream operations (defaults to T)
|
|
19
21
|
*/
|
|
20
|
-
export declare abstract class CsvEntity<T, S = T>
|
|
22
|
+
export declare abstract class CsvEntity<T, S = T> {
|
|
21
23
|
byteBuffer: ByteBuffer;
|
|
22
24
|
separator: string;
|
|
23
25
|
escapeChar: string;
|
|
26
|
+
newline?: string;
|
|
24
27
|
consumed: boolean;
|
|
25
28
|
/**
|
|
26
29
|
* Creates a new CSV entity.
|
|
@@ -96,6 +99,19 @@ export declare abstract class CsvEntity<T, S = T> implements Required<CsvEntityO
|
|
|
96
99
|
export declare class CsvCell extends CsvEntity<string> {
|
|
97
100
|
chunkSize: number;
|
|
98
101
|
endOfLineReached: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Checks if the current buffer position starts with a line ending.
|
|
104
|
+
* Supports both default line endings (\r, \n, \r\n) and custom newline strings.
|
|
105
|
+
*
|
|
106
|
+
* @returns true if at the start of a line ending, false otherwise
|
|
107
|
+
*/
|
|
108
|
+
private isAtLineEnd;
|
|
109
|
+
/**
|
|
110
|
+
* Consumes a line ending from the buffer.
|
|
111
|
+
* Handles both default line endings (\r, \n, \r\n) and custom newline strings.
|
|
112
|
+
* Should only be called after isAtLineEnd() returns true.
|
|
113
|
+
*/
|
|
114
|
+
private consumeLineEnd;
|
|
99
115
|
protected parse(): string;
|
|
100
116
|
protected parseAsync(): Promise<string>;
|
|
101
117
|
/**
|
package/dist/parser.js
CHANGED
|
@@ -31,6 +31,7 @@ export class CsvEntity {
|
|
|
31
31
|
byteBuffer;
|
|
32
32
|
separator = ',';
|
|
33
33
|
escapeChar = '"';
|
|
34
|
+
newline;
|
|
34
35
|
consumed = false;
|
|
35
36
|
/**
|
|
36
37
|
* Creates a new CSV entity.
|
|
@@ -49,6 +50,19 @@ export class CsvEntity {
|
|
|
49
50
|
if (options?.escapeChar) {
|
|
50
51
|
this.escapeChar = options.escapeChar;
|
|
51
52
|
}
|
|
53
|
+
if (options?.newline !== undefined) {
|
|
54
|
+
const newline = options.newline;
|
|
55
|
+
if (newline === '') {
|
|
56
|
+
throw new Error('Invalid CSV newline: newline option must be a non-empty string.');
|
|
57
|
+
}
|
|
58
|
+
if (newline.includes(this.separator)) {
|
|
59
|
+
throw new Error('Invalid CSV newline: newline option must not contain the field separator character.');
|
|
60
|
+
}
|
|
61
|
+
if (newline.includes(this.escapeChar)) {
|
|
62
|
+
throw new Error('Invalid CSV newline: newline option must not contain the escape character.');
|
|
63
|
+
}
|
|
64
|
+
this.newline = newline;
|
|
65
|
+
}
|
|
52
66
|
}
|
|
53
67
|
set maxBufferSize(size) {
|
|
54
68
|
this.byteBuffer.maxBufferSize = size;
|
|
@@ -162,6 +176,55 @@ export class CsvEntity {
|
|
|
162
176
|
export class CsvCell extends CsvEntity {
|
|
163
177
|
chunkSize = DEFAULT_CHUNK_SIZE;
|
|
164
178
|
endOfLineReached = false;
|
|
179
|
+
/**
|
|
180
|
+
* Checks if the current buffer position starts with a line ending.
|
|
181
|
+
* Supports both default line endings (\r, \n, \r\n) and custom newline strings.
|
|
182
|
+
*
|
|
183
|
+
* @returns true if at the start of a line ending, false otherwise
|
|
184
|
+
*/
|
|
185
|
+
isAtLineEnd() {
|
|
186
|
+
if (this.newline !== undefined) {
|
|
187
|
+
// Check for custom newline string
|
|
188
|
+
for (let i = 0; i < this.newline.length; i++) {
|
|
189
|
+
const expectedByte = this.newline.charCodeAt(i);
|
|
190
|
+
const actualByte = this.byteBuffer.peek(i);
|
|
191
|
+
if (actualByte === null || actualByte !== expectedByte) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
// Default behavior: check for \r or \n
|
|
199
|
+
return isLineEnd(this.byteBuffer.peek());
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Consumes a line ending from the buffer.
|
|
204
|
+
* Handles both default line endings (\r, \n, \r\n) and custom newline strings.
|
|
205
|
+
* Should only be called after isAtLineEnd() returns true.
|
|
206
|
+
*/
|
|
207
|
+
consumeLineEnd() {
|
|
208
|
+
if (this.newline !== undefined) {
|
|
209
|
+
// Consume custom newline string - verify each byte matches
|
|
210
|
+
for (let i = 0; i < this.newline.length; i++) {
|
|
211
|
+
const expectedByte = this.newline.charCodeAt(i);
|
|
212
|
+
const actualByte = this.byteBuffer.peek();
|
|
213
|
+
if (actualByte === null || actualByte !== expectedByte) {
|
|
214
|
+
throw new Error('Invariant violation: consumeLineEnd called when not at line end');
|
|
215
|
+
}
|
|
216
|
+
this.byteBuffer.next();
|
|
217
|
+
}
|
|
218
|
+
this.endOfLineReached = true;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
// Default behavior: consume \r and/or \n
|
|
222
|
+
while (isLineEnd(this.byteBuffer.peek())) {
|
|
223
|
+
this.byteBuffer.next();
|
|
224
|
+
this.endOfLineReached = true;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
165
228
|
parse() {
|
|
166
229
|
let str = '';
|
|
167
230
|
for (const part of this) {
|
|
@@ -240,7 +303,7 @@ export class CsvCell extends CsvEntity {
|
|
|
240
303
|
}
|
|
241
304
|
}
|
|
242
305
|
else {
|
|
243
|
-
if (next === separator ||
|
|
306
|
+
if (next === separator || this.isAtLineEnd()) {
|
|
244
307
|
break;
|
|
245
308
|
}
|
|
246
309
|
}
|
|
@@ -258,9 +321,8 @@ export class CsvCell extends CsvEntity {
|
|
|
258
321
|
if (this.byteBuffer.peek() === separator) {
|
|
259
322
|
this.byteBuffer.expect(separator); // consume separator
|
|
260
323
|
}
|
|
261
|
-
|
|
262
|
-
this.
|
|
263
|
-
this.endOfLineReached = true;
|
|
324
|
+
if (this.isAtLineEnd()) {
|
|
325
|
+
this.consumeLineEnd();
|
|
264
326
|
}
|
|
265
327
|
if (!hadData || chunk.length > 0)
|
|
266
328
|
yield bytesToString(new Uint8Array(chunk));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "csv-stream-lite",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
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",
|