Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add skipEmptyLines and extendedRangeError #229

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,13 @@ Default: `0`
Specifies the number of lines at the beginning of a data file that the parser should
skip over, prior to parsing headers.

#### skipEmptyLines

Type: `Boolean`<br>
Default: `false`

If `true`, empty lines are skipped.

#### maxRowBytes

Type: `Number`<br>
Expand All @@ -259,6 +266,13 @@ if `false`: the headers are mapped to the column index
less columns: any missing column in the middle will result in a wrong property mapping!
more columns: the aditional columns will create a "_"+index properties - eg. "_10":"value"

#### extendedRangeError

Type: `Boolean`<br>
Default: `false`

If `true`, then `lineNumber`, `cells`, `line` are added to the error object.

## Events

The following events are emitted during parsing:
Expand Down Expand Up @@ -305,6 +319,7 @@ Usage: csv-parser [filename?] [options]
--separator,-s Set the separator character ("," by default)
--skipComments,-c Skip CSV comments that begin with '#'. Set a value to change the comment character.
--skipLines,-l Set the number of lines to skip to before parsing headers
--skipEmptyLines Skip empty lines
--strict Require column length match headers length
--version,-v Print out the installed version
```
Expand Down
4 changes: 3 additions & 1 deletion bin/csv-parser
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ if (argv.help || (process.stdin.isTTY && !filename)) {
--separator,-s Set the separator character ("," by default)
--skipComments,-c Skip CSV comments that begin with '#'. Set a value to change the comment character.
--skipLines,-l Set the number of lines to skip to before parsing headers
--skipEmptyLines Skip empty lines
--strict Require column length match headers length
--version,-v Print out the installed version
`)
Expand All @@ -56,7 +57,8 @@ const options = {
separator: argv.separator,
strict: argv.strict,
skipComments: argv.skipComments,
skipLines: argv.skipLines
skipLines: argv.skipLines,
skipEmptyLines: argv.skipEmptyLines
}

if (argv.headers) {
Expand Down
12 changes: 12 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ Bugs Bunny,22
*/
readonly skipLines?: number;

/**
* If true empty lines are skipped.
*
* @default false
*/
readonly skipEmptyLines?: boolean;

/**
* Maximum number of bytes per row. An error is thrown if a line exeeds this value. The default value is on 8 peta byte.
*
Expand All @@ -107,6 +114,11 @@ Bugs Bunny,22
* If `true`, instructs the parser that the number of columns in each row must match the number of `headers` specified.
*/
readonly strict?: boolean;

/**
* If `true`, then `lineNumber`, `cells`, `line` are added to the error object.
*/
readonly extendedRangeError?: boolean;
}
}

Expand Down
20 changes: 15 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,21 @@ class CsvParser extends Transform {
return
}

if (!skip && this.options.strict && cells.length !== this.headers.length) {
const e = new RangeError('Row length does not match headers')
this.emit('error', e)
} else {
if (!skip) this.writeRow(cells)
if (!skip) {
if (start === end && this.options.skipEmptyLines) {
return
}
if (this.options.strict && cells.length !== this.headers.length) {
const e = new RangeError('Row length does not match headers')
if (this.options.extendedRangeError) {
e.lineNumber = this.state.lineNumber
e.cells = cells
e.line = buffer.toString('utf-8', start, end)
}
this.emit('error', e)
} else {
this.writeRow(cells)
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@ expectType<csvParser.CsvParser>(csvParser({ separator: ',' }));
expectType<csvParser.CsvParser>(csvParser({ skipComments: true }));
expectType<csvParser.CsvParser>(csvParser({ skipComments: '#' }));
expectType<csvParser.CsvParser>(csvParser({ skipLines: 1 }));
expectType<csvParser.CsvParser>(csvParser({ skipEmptyLines: false }));
expectType<csvParser.CsvParser>(csvParser({ maxRowBytes: 1 }));
expectType<csvParser.CsvParser>(csvParser({ strict: true }));
expectType<csvParser.CsvParser>(csvParser({ extendedRangeError: false }));
14 changes: 14 additions & 0 deletions test/extendedRangeError.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const test = require('ava')

const { collect } = require('./helpers/helper')

test.cb('extended range error', (t) => {
const verify = (err, lines) => {
t.is(err.lineNumber, 2, 'lineNumber set')
t.is(err.cells.length, 1, 'cells returned')
t.is(err.line, '1', 'line returned')
t.end()
}

collect('option-extendedRangeError', { columns: true, strict: true, extendedRangeError: true }, verify)
})
2 changes: 2 additions & 0 deletions test/fixtures/option-extendedRangeError.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
A,B
1
7 changes: 7 additions & 0 deletions test/fixtures/option-skipEmptyLines.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
A

1
2


3
17 changes: 17 additions & 0 deletions test/skipEmptyLines.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const test = require('ava')

const { collect } = require('./helpers/helper')

test.cb('skip empty lines', (t) => {
const verify = (err, lines) => {
console.log(lines)
t.false(err, 'no err')
t.is(lines.length, 3, '3 row')
t.is(JSON.stringify(lines[0]), JSON.stringify({ A: '1' }))
t.is(JSON.stringify(lines[1]), JSON.stringify({ A: '2' }))
t.is(JSON.stringify(lines[2]), JSON.stringify({ A: '3' }))
t.end()
}

collect('option-skipEmptyLines', { skipEmptyLines: true, columns: true, strict: true }, verify)
})