Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

csv-parse

Package Overview
Dependencies
Maintainers
1
Versions
141
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

csv-parse - npm Package Compare versions

Comparing version 4.15.4 to 4.16.0

21

CHANGELOG.md

@@ -6,4 +6,6 @@

Please join and contribute:
Below is the list of upgrades we are considering for the next major release. The majority of them are just simple refactoring. They will however introduce backward incompatibilities.
We invite you to join and contribute but create an issue before engaging any work. Some tasks are scheduled for another time or might depends on another one.
* `skip_lines_with_empty_values`: rename to skip_records_with_empty_values (easy)

@@ -16,7 +18,16 @@ * `skip_lines_with_error`: rename to skip_records_with_error (easy)

* encoding: new encoding_input and encoding_output options (medium)
* context: isolate info properties at context root (easy)
* context: merge record, raw, context, info, error into a single object (medium)
* relax_column_count: rename INCONSISTENT_RECORD_LENGTH to RECORD_INCONSISTENT_FIELDS_LENGTH (easy)
* relax_column_count: rename RECORD_DONT_MATCH_COLUMNS_LENGTH to RECORD_INCONSISTENT_COLUMNS (easy)
* `columns_duplicates_to_array`: this is just too long but I don't have much insipiration for a better name
* `relax_column_count`: rename INCONSISTENT_RECORD_LENGTH to RECORD_INCONSISTENT_FIELDS_LENGTH (easy)
* `relax_column_count`: rename RECORD_DONT_MATCH_COLUMNS_LENGTH to RECORD_INCONSISTENT_COLUMNS (easy)
* `info`: remove the `parser.info` object and move its properties to `state`
* `info`: rename the `info` related properties and functions to `context`
## Version 4.16.0
* fix: info print the number of encountered line when emited
* feat: cast expose context.empty_lines
* fix: handle empty column names properly
* feat: enforce usage of columns with columns_duplicates_to_array
* fix: update error message with invalid column type
## Version 4.15.4

@@ -23,0 +34,0 @@

@@ -180,3 +180,3 @@ "use strict";

} else {
throw new CsvError('CSV_INVALID_OPTION_COLUMNS', ['Invalid option columns:', 'expect an object, a function or true,', "got ".concat(JSON.stringify(options.columns))], options);
throw new CsvError('CSV_INVALID_OPTION_COLUMNS', ['Invalid option columns:', 'expect an array, a function or true,', "got ".concat(JSON.stringify(options.columns))], options);
} // Normalize option `columns_duplicates_to_array`

@@ -189,2 +189,4 @@

throw new CsvError('CSV_INVALID_OPTION_COLUMNS_DUPLICATES_TO_ARRAY', ['Invalid option columns_duplicates_to_array:', 'expect an boolean,', "got ".concat(JSON.stringify(options.columns_duplicates_to_array))], options);
} else if (options.columns === false) {
throw new CsvError('CSV_INVALID_OPTION_COLUMNS_DUPLICATES_TO_ARRAY', ['Invalid option columns_duplicates_to_array:', 'the `columns` mode must be activated.'], options);
} // Normalize option `comment`

@@ -515,6 +517,6 @@

escapeIsQuote: Buffer.isBuffer(options.escape) && Buffer.isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0,
expectedRecordLength: options.columns === null ? 0 : options.columns.length,
// columns can be `false`, `true`, `Array`
expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined,
field: new ResizeableBuffer(20),
firstLineToHeaders: fnFirstLineToHeaders,
info: Object.assign({}, this.info),
needMoreDataSize: Math.max.apply(Math, [// Skip if the remaining buffer smaller than comment

@@ -577,3 +579,2 @@ options.comment !== null ? options.comment.length : 0].concat(_toConsumableArray(options.delimiter.map(function (delimiter) {

from_line = _this$options.from_line,
info = _this$options.info,
ltrim = _this$options.ltrim,

@@ -651,7 +652,2 @@ max_record_size = _this$options.max_record_size,

this.info.lines++;
if (info === true && this.state.record.length === 0 && this.state.field.length === 0 && this.state.wasQuoting === false) {
this.state.info = Object.assign({}, this.info);
}
this.state.wasRowDelimiter = false;

@@ -730,3 +726,3 @@ }

} else if (relax === false) {
var err = this.__error(new CsvError('CSV_INVALID_CLOSING_QUOTE', ['Invalid Closing Quote:', "got \"".concat(String.fromCharCode(nextChr), "\""), "at line ".concat(this.info.lines), 'instead of delimiter, record delimiter, trimable character', '(if activated) or comment'], this.options, this.__context()));
var err = this.__error(new CsvError('CSV_INVALID_CLOSING_QUOTE', ['Invalid Closing Quote:', "got \"".concat(String.fromCharCode(nextChr), "\""), "at line ".concat(this.info.lines), 'instead of delimiter, record delimiter, trimable character', '(if activated) or comment'], this.options, this.__infoField()));

@@ -744,3 +740,3 @@ if (err !== undefined) return err;

if (relax === false) {
var _err = this.__error(new CsvError('INVALID_OPENING_QUOTE', ['Invalid Opening Quote:', "a quote is found inside a field at line ".concat(this.info.lines)], this.options, this.__context(), {
var _err = this.__error(new CsvError('INVALID_OPENING_QUOTE', ['Invalid Opening Quote:', "a quote is found inside a field at line ".concat(this.info.lines)], this.options, this.__infoField(), {
field: this.state.field

@@ -833,3 +829,3 @@ }));

if (max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size) {
var _err2 = this.__error(new CsvError('CSV_MAX_RECORD_SIZE', ['Max Record Size:', 'record exceed the maximum number of tolerated bytes', "of ".concat(max_record_size), "at line ".concat(this.info.lines)], this.options, this.__context()));
var _err2 = this.__error(new CsvError('CSV_MAX_RECORD_SIZE', ['Max Record Size:', 'record exceed the maximum number of tolerated bytes', "of ".concat(max_record_size), "at line ".concat(this.info.lines)], this.options, this.__infoField()));

@@ -847,3 +843,3 @@ if (_err2 !== undefined) return _err2;

} else if (rtrim === true && !this.__isCharTrimable(chr)) {
var _err3 = this.__error(new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', ['Invalid Closing Quote:', 'found non trimable byte after quote', "at line ".concat(this.info.lines)], this.options, this.__context()));
var _err3 = this.__error(new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', ['Invalid Closing Quote:', 'found non trimable byte after quote', "at line ".concat(this.info.lines)], this.options, this.__infoField()));

@@ -857,3 +853,3 @@ if (_err3 !== undefined) return _err3;

if (this.state.quoting === true) {
var _err4 = this.__error(new CsvError('CSV_QUOTE_NOT_CLOSED', ['Quote Not Closed:', "the parsing is finished with an opening quote at line ".concat(this.info.lines)], this.options, this.__context()));
var _err4 = this.__error(new CsvError('CSV_QUOTE_NOT_CLOSED', ['Quote Not Closed:', "the parsing is finished with an opening quote at line ".concat(this.info.lines)], this.options, this.__infoField()));

@@ -912,3 +908,3 @@ if (_err4 !== undefined) return _err4;

if (columns === true) {
if (isRecordEmpty(record)) {
if (skip_lines_with_empty_values === true && isRecordEmpty(record)) {
this.__resetRecord();

@@ -929,3 +925,3 @@

// CSV_RECORD_INCONSISTENT_FIELDS_LENGTH
new CsvError('CSV_INCONSISTENT_RECORD_LENGTH', ['Invalid Record Length:', "expect ".concat(this.state.expectedRecordLength, ","), "got ".concat(recordLength, " on line ").concat(this.info.lines)], this.options, this.__context(), {
new CsvError('CSV_INCONSISTENT_RECORD_LENGTH', ['Invalid Record Length:', "expect ".concat(this.state.expectedRecordLength, ","), "got ".concat(recordLength, " on line ").concat(this.info.lines)], this.options, this.__infoField(), {
record: record

@@ -935,3 +931,3 @@ }) : // Todo: rename CSV_RECORD_DONT_MATCH_COLUMNS_LENGTH to

new CsvError('CSV_RECORD_DONT_MATCH_COLUMNS_LENGTH', ['Invalid Record Length:', "columns length is ".concat(columns.length, ","), // rename columns
"got ".concat(recordLength, " on line ").concat(this.info.lines)], this.options, this.__context(), {
"got ".concat(recordLength, " on line ").concat(this.info.lines)], this.options, this.__infoField(), {
record: record

@@ -950,8 +946,6 @@ });

if (skip_lines_with_empty_values === true) {
if (isRecordEmpty(record)) {
this.__resetRecord();
if (skip_lines_with_empty_values === true && isRecordEmpty(record)) {
this.__resetRecord();
return;
}
return;
}

@@ -969,2 +963,3 @@

if (from === 1 || this.info.records >= from) {
// With columns, records are object
if (columns !== false) {

@@ -987,3 +982,3 @@ var obj = {}; // Transform record array to an object

var objname = this.options.objname;
var objname = this.options.objname; // Without objname (default)

@@ -997,3 +992,3 @@ if (objname === undefined) {

} : {}, info === true ? {
info: this.state.info
info: this.__infoRecord()
} : {}));

@@ -1010,3 +1005,4 @@

}
}
} // With objname (default)
} else {

@@ -1019,3 +1015,3 @@ if (raw === true || info === true) {

} : {}, info === true ? {
info: this.state.info
info: this.__infoRecord()
} : {}));

@@ -1033,3 +1029,4 @@

}
}
} // Without columns, records are array
} else {

@@ -1042,3 +1039,3 @@ if (raw === true || info === true) {

} : {}, info === true ? {
info: this.state.info
info: this.__infoRecord()
} : {}));

@@ -1070,3 +1067,3 @@

if (!Array.isArray(headers)) {
return this.__error(new CsvError('CSV_INVALID_COLUMN_MAPPING', ['Invalid Column Mapping:', 'expect an array from column function,', "got ".concat(JSON.stringify(headers))], this.options, this.__context(), {
return this.__error(new CsvError('CSV_INVALID_COLUMN_MAPPING', ['Invalid Column Mapping:', 'expect an array from column function,', "got ".concat(JSON.stringify(headers))], this.options, this.__infoField(), {
headers: headers

@@ -1111,3 +1108,2 @@ }));

if (enabled === false) {
/* this.options.columns !== true && */
return this.__resetField();

@@ -1152,6 +1148,6 @@ }

if (on_record !== undefined) {
var context = this.__context();
var info = this.__infoRecord();
try {
record = on_record.call(null, record, context);
record = on_record.call(null, record, info);
} catch (err) {

@@ -1183,7 +1179,7 @@ return err;

var context = this.__context();
if (this.state.castField !== null) {
try {
return [undefined, this.state.castField.call(null, field, context)];
var info = this.__infoField();
return [undefined, this.state.castField.call(null, field, info)];
} catch (err) {

@@ -1197,3 +1193,5 @@ return [err];

} else if (this.options.cast_date !== false) {
return [undefined, this.options.cast_date.call(null, field, context)];
var _info = this.__infoField();
return [undefined, this.options.cast_date.call(null, field, _info)];
}

@@ -1373,18 +1371,28 @@

}, {
key: "__context",
value: function __context() {
key: "__infoDataSet",
value: function __infoDataSet() {
return _objectSpread(_objectSpread({}, this.info), {}, {
columns: this.options.columns
});
}
}, {
key: "__infoRecord",
value: function __infoRecord() {
var columns = this.options.columns;
var isColumns = Array.isArray(columns);
return {
column: isColumns === true ? columns.length > this.state.record.length ? columns[this.state.record.length].name : null : this.state.record.length,
empty_lines: this.info.empty_lines,
return _objectSpread(_objectSpread({}, this.__infoDataSet()), {}, {
error: this.state.error,
header: columns === true,
index: this.state.record.length,
invalid_field_length: this.info.invalid_field_length,
quoting: this.state.wasQuoting,
lines: this.info.lines,
records: this.info.records
};
index: this.state.record.length
});
}
}, {
key: "__infoField",
value: function __infoField() {
var columns = this.options.columns;
var isColumns = Array.isArray(columns);
return _objectSpread(_objectSpread({}, this.__infoRecord()), {}, {
column: isColumns === true ? columns.length > this.state.record.length ? columns[this.state.record.length].name : null : this.state.record.length,
quoting: this.state.wasQuoting
});
}
}]);

@@ -1430,6 +1438,6 @@

parser.on('error', function (err) {
callback(err, undefined, parser.info);
callback(err, undefined, parser.__infoDataSet());
});
parser.on('end', function () {
callback(undefined, records, parser.info);
callback(undefined, records, parser.__infoDataSet());
});

@@ -1436,0 +1444,0 @@ }

@@ -110,3 +110,3 @@

'Invalid option columns:',
'expect an object, a function or true,',
'expect an array, a function or true,',
`got ${JSON.stringify(options.columns)}`

@@ -124,2 +124,7 @@ ], options)

], options)
}else if(options.columns === false){
throw new CsvError('CSV_INVALID_OPTION_COLUMNS_DUPLICATES_TO_ARRAY', [
'Invalid option columns_duplicates_to_array:',
'the `columns` mode must be activated.'
], options)
}

@@ -439,6 +444,6 @@ // Normalize option `comment`

escapeIsQuote: Buffer.isBuffer(options.escape) && Buffer.isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0,
expectedRecordLength: options.columns === null ? 0 : options.columns.length,
// columns can be `false`, `true`, `Array`
expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined,
field: new ResizeableBuffer(20),
firstLineToHeaders: fnFirstLineToHeaders,
info: Object.assign({}, this.info),
needMoreDataSize: Math.max(

@@ -486,3 +491,3 @@ // Skip if the remaining buffer smaller than comment

__parse(nextBuf, end){
const {bom, comment, escape, from_line, info, ltrim, max_record_size, quote, raw, relax, rtrim, skip_empty_lines, to, to_line} = this.options
const {bom, comment, escape, from_line, ltrim, max_record_size, quote, raw, relax, rtrim, skip_empty_lines, to, to_line} = this.options
let {record_delimiter} = this.options

@@ -538,5 +543,2 @@ const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state

this.info.lines++
if(info === true && this.state.record.length === 0 && this.state.field.length === 0 && this.state.wasQuoting === false){
this.state.info = Object.assign({}, this.info)
}
this.state.wasRowDelimiter = false

@@ -610,3 +612,3 @@ }

'(if activated) or comment',
], this.options, this.__context())
], this.options, this.__infoField())
)

@@ -628,3 +630,3 @@ if(err !== undefined) return err

`a quote is found inside a field at line ${this.info.lines}`,
], this.options, this.__context(), {
], this.options, this.__infoField(), {
field: this.state.field,

@@ -704,3 +706,3 @@ })

`at line ${this.info.lines}`,
], this.options, this.__context())
], this.options, this.__infoField())
)

@@ -710,3 +712,2 @@ if(err !== undefined) return err

}
const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(chr)

@@ -723,3 +724,3 @@ // rtrim in non quoting is handle in __onField

`at line ${this.info.lines}`,
], this.options, this.__context())
], this.options, this.__infoField())
)

@@ -736,3 +737,3 @@ if(err !== undefined) return err

`the parsing is finished with an opening quote at line ${this.info.lines}`,
], this.options, this.__context())
], this.options, this.__infoField())
)

@@ -770,3 +771,3 @@ if(err !== undefined) return err

if(columns === true){
if(isRecordEmpty(record)){
if(skip_lines_with_empty_values === true && isRecordEmpty(record)){
this.__resetRecord()

@@ -788,3 +789,3 @@ return

`got ${recordLength} on line ${this.info.lines}`,
], this.options, this.__context(), {
], this.options, this.__infoField(), {
record: record,

@@ -799,3 +800,3 @@ })

`got ${recordLength} on line ${this.info.lines}`,
], this.options, this.__context(), {
], this.options, this.__infoField(), {
record: record,

@@ -814,7 +815,5 @@ })

}
if(skip_lines_with_empty_values === true){
if(isRecordEmpty(record)){
this.__resetRecord()
return
}
if(skip_lines_with_empty_values === true && isRecordEmpty(record)){
this.__resetRecord()
return
}

@@ -828,2 +827,3 @@ if(this.state.recordHasError === true){

if(from === 1 || this.info.records >= from){
// With columns, records are object
if(columns !== false){

@@ -846,2 +846,3 @@ const obj = {}

const {objname} = this.options
// Without objname (default)
if(objname === undefined){

@@ -852,3 +853,3 @@ if(raw === true || info === true){

(raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}),
(info === true ? {info: this.state.info}: {})
(info === true ? {info: this.__infoRecord()}: {})
))

@@ -864,2 +865,3 @@ if(err){

}
// With objname (default)
}else{

@@ -870,3 +872,3 @@ if(raw === true || info === true){

raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {},
info === true ? {info: this.state.info}: {}
info === true ? {info: this.__infoRecord()}: {}
))

@@ -883,2 +885,3 @@ if(err){

}
// Without columns, records are array
}else{

@@ -889,3 +892,3 @@ if(raw === true || info === true){

raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {},
info === true ? {info: this.state.info}: {}
info === true ? {info: this.__infoRecord()}: {}
))

@@ -915,3 +918,3 @@ if(err){

`got ${JSON.stringify(headers)}`
], this.options, this.__context(), {
], this.options, this.__infoField(), {
headers: headers,

@@ -942,3 +945,3 @@ })

// Short circuit for the from_line options
if(enabled === false){ /* this.options.columns !== true && */
if(enabled === false){
return this.__resetField()

@@ -969,5 +972,5 @@ }

if(on_record !== undefined){
const context = this.__context()
const info = this.__infoRecord()
try{
record = on_record.call(null, record, context)
record = on_record.call(null, record, info)
}catch(err){

@@ -990,6 +993,6 @@ return err

}
const context = this.__context()
if(this.state.castField !== null){
try{
return [undefined, this.state.castField.call(null, field, context)]
const info = this.__infoField()
return [undefined, this.state.castField.call(null, field, info)]
}catch(err){

@@ -1002,3 +1005,4 @@ return [err]

}else if(this.options.cast_date !== false){
return [undefined, this.options.cast_date.call(null, field, context)]
const info = this.__infoField()
return [undefined, this.options.cast_date.call(null, field, info)]
}

@@ -1135,6 +1139,22 @@ return [undefined, field]

}
__context(){
__infoDataSet(){
return {
...this.info,
columns: this.options.columns
}
}
__infoRecord(){
const {columns} = this.options
return {
...this.__infoDataSet(),
error: this.state.error,
header: columns === true,
index: this.state.record.length,
}
}
__infoField(){
const {columns} = this.options
const isColumns = Array.isArray(columns)
return {
...this.__infoRecord(),
column: isColumns === true ?

@@ -1146,10 +1166,3 @@ ( columns.length > this.state.record.length ?

this.state.record.length,
empty_lines: this.info.empty_lines,
error: this.state.error,
header: columns === true,
index: this.state.record.length,
invalid_field_length: this.info.invalid_field_length,
quoting: this.state.wasQuoting,
lines: this.info.lines,
records: this.info.records
}

@@ -1191,6 +1204,6 @@ }

parser.on('error', function(err){
callback(err, undefined, parser.info)
callback(err, undefined, parser.__infoDataSet())
})
parser.on('end', function(){
callback(undefined, records, parser.info)
callback(undefined, records, parser.__infoDataSet())
})

@@ -1197,0 +1210,0 @@ }

{
"version": "4.15.4",
"version": "4.16.0",
"name": "csv-parse",

@@ -4,0 +4,0 @@ "description": "CSV parsing implementing the Node.js `stream.Transform` API",

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc