Skip to content

Commit 1326351

Browse files
committed
fix(csv-parse): skip event not raised with bom (fix #411)
1 parent 41fca27 commit 1326351

File tree

4 files changed

+52
-41
lines changed

4 files changed

+52
-41
lines changed

demo/issues-esm/lib/411.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
id,first_name,last_name,email,modified_at
1+
id,first_name,last_name,email,modified_at
22
1,Ring,Grinyov,[email protected],2022-02-14
33
2,Kylie,Lauderdale,[email protected],2022-02-14,
44
3,Cammi,Bendix,[email protected],2022-02-14

demo/issues-esm/lib/411.js

+24-35
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,27 @@
1-
import path from 'path';
2-
import { pipeline } from 'stream/promises';
3-
import { parse as parseCSV } from 'csv-parse';
4-
import { Writable } from 'stream';
5-
import { createReadStream } from 'fs';
1+
import assert from 'node:assert';
2+
import { createReadStream } from 'node:fs';
3+
import { Writable } from 'node:stream'
4+
import { finished } from 'node:stream/promises';
65
import desm from "desm";
7-
const __dirname = desm(import.meta.url);
8-
9-
async function testRecordsSkip() {
10-
const errors = [];
11-
const records = [];
12-
13-
const sink = new Writable({
14-
objectMode: true,
15-
write: (_, __, callback) => {
16-
records.push(_);
17-
callback();
18-
},
19-
});
6+
import { parse } from 'csv-parse';
207

21-
const csvSource = createReadStream(path.join(__dirname, '411.csv'));
22-
const parser = parseCSV({
23-
skip_records_with_error: true,
24-
bom: true,
25-
});
26-
parser.on('skip', function (err) {
27-
errors.push(err);
28-
});
29-
30-
await pipeline(csvSource, parser, sink);
31-
32-
console.log({
33-
records,
34-
errors,
35-
});
36-
}
8+
const __dirname = desm(import.meta.url);
9+
const errors = []
3710

38-
testRecordsSkip().catch(console.error);
11+
const parser = parse({
12+
bom: true,
13+
skipRecordsWithError: true,
14+
});
15+
// Create a stream and consume its source
16+
const sink = new Writable ({objectMode: true, write: (_, __, callback) => callback()})
17+
const outStream = createReadStream(`${__dirname}/411.csv`).pipe(parser).pipe(sink);
18+
// Catch records with errors
19+
parser.on('skip', (e) => {
20+
errors.push(e);
21+
});
22+
// Wait for stream to be consumed
23+
await finished(outStream);
24+
// Catch error from skip event
25+
assert.deepStrictEqual(errors.map(e => e.message), [
26+
'Invalid Record Length: expect 5, got 6 on line 3'
27+
])

packages/csv-parse/lib/index.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ import {CsvError} from './api/CsvError.js';
1414
class Parser extends Transform {
1515
constructor(opts = {}){
1616
super({...{readableObjectMode: true}, ...opts, encoding: null});
17-
this.api = transform(opts);
18-
this.api.options.on_skip = (err, chunk) => {
17+
this.api = transform({on_skip: (err, chunk) => {
1918
this.emit('skip', err, chunk);
20-
};
19+
}, ...opts});
2120
// Backward compatibility
2221
this.state = this.api.state;
2322
this.options = this.api.options;

packages/csv-parse/test/option.skip_records_with_error.coffee

+25-2
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,7 @@ describe 'Option `skip_records_with_error`', ->
106106
7,8,9,y
107107
'''
108108
parser.end()
109-
110-
109+
111110
it 'handle "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH"', (next) ->
112111
errors = 0
113112
parser = parse skip_records_with_error: true, (err, records) ->
@@ -130,6 +129,30 @@ describe 'Option `skip_records_with_error`', ->
130129
'''
131130
parser.end()
132131

132+
describe 'with `bom` option', ->
133+
134+
it 'handle "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH" with bom (fix #411)', (next) ->
135+
errors = 0
136+
parser = parse bom: true, skip_records_with_error: true, (err, records) ->
137+
records.should.eql [
138+
['a', 'b', 'c', 'd']
139+
['e', 'f', 'g', 'h']
140+
] unless err
141+
errors.should.eql 1
142+
next err
143+
parser.on 'skip', (err) ->
144+
assert_error err,
145+
message: 'Invalid Record Length: expect 4, got 3 on line 2'
146+
code: 'CSV_RECORD_INCONSISTENT_FIELDS_LENGTH'
147+
record: ['1', '2', '3']
148+
errors++
149+
parser.write '''
150+
\ufeffa,b,c,d
151+
1,2,3
152+
e,f,g,h
153+
'''
154+
parser.end()
155+
133156
describe 'with `raw` option', ->
134157

135158
it 'print raw record', (next) ->

0 commit comments

Comments
 (0)