diff --git a/README.md b/README.md
index bfd4b31..64eca77 100644
--- a/README.md
+++ b/README.md
@@ -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`
+Default: `false`
+
+If `true`, empty lines are skipped.
+
#### maxRowBytes
Type: `Number`
@@ -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`
+Default: `false`
+
+If `true`, then `lineNumber`, `cells`, `line` are added to the error object.
+
## Events
The following events are emitted during parsing:
@@ -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
```
diff --git a/bin/csv-parser b/bin/csv-parser
index f895a8e..f3b23fb 100755
--- a/bin/csv-parser
+++ b/bin/csv-parser
@@ -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
`)
@@ -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) {
diff --git a/index.d.ts b/index.d.ts
index a6a400d..ad2f529 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -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.
*
@@ -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;
}
}
diff --git a/index.js b/index.js
index 2a6a2da..7b41d9a 100644
--- a/index.js
+++ b/index.js
@@ -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)
+ }
}
}
diff --git a/index.test-d.ts b/index.test-d.ts
index 703330e..9b46bd3 100644
--- a/index.test-d.ts
+++ b/index.test-d.ts
@@ -36,5 +36,7 @@ expectType(csvParser({ separator: ',' }));
expectType(csvParser({ skipComments: true }));
expectType(csvParser({ skipComments: '#' }));
expectType(csvParser({ skipLines: 1 }));
+expectType(csvParser({ skipEmptyLines: false }));
expectType(csvParser({ maxRowBytes: 1 }));
expectType(csvParser({ strict: true }));
+expectType(csvParser({ extendedRangeError: false }));
diff --git a/test/extendedRangeError.test.js b/test/extendedRangeError.test.js
new file mode 100644
index 0000000..c02b28c
--- /dev/null
+++ b/test/extendedRangeError.test.js
@@ -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)
+})
diff --git a/test/fixtures/option-extendedRangeError.csv b/test/fixtures/option-extendedRangeError.csv
new file mode 100644
index 0000000..1fc698d
--- /dev/null
+++ b/test/fixtures/option-extendedRangeError.csv
@@ -0,0 +1,2 @@
+A,B
+1
diff --git a/test/fixtures/option-skipEmptyLines.csv b/test/fixtures/option-skipEmptyLines.csv
new file mode 100644
index 0000000..96083f6
--- /dev/null
+++ b/test/fixtures/option-skipEmptyLines.csv
@@ -0,0 +1,7 @@
+A
+
+1
+2
+
+
+3
diff --git a/test/skipEmptyLines.test.js b/test/skipEmptyLines.test.js
new file mode 100644
index 0000000..90ab778
--- /dev/null
+++ b/test/skipEmptyLines.test.js
@@ -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)
+})