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

fast-csv

Package Overview
Dependencies
Maintainers
2
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fast-csv - npm Package Compare versions

Comparing version 3.2.0 to 3.3.0

2

build/src/formatter/formatter/RowFormatter.d.ts

@@ -12,3 +12,3 @@ import { FormatterOptions } from '../FormatterOptions';

private headers;
private parsedHeaders;
private shouldWriteHeaders;
private hasWrittenHeaders;

@@ -15,0 +15,0 @@ private rowCount;

@@ -12,5 +12,5 @@ "use strict";

this.headers = formatterOptions.headers;
this.parsedHeaders = formatterOptions.hasProvidedHeaders && Array.isArray(formatterOptions.headers);
this.hasWrittenHeaders = !formatterOptions.hasProvidedHeaders;
if (this.parsedHeaders && this.headers !== null) {
this.shouldWriteHeaders = formatterOptions.shouldWriteHeaders;
this.hasWrittenHeaders = false;
if (this.headers !== null) {
this.fieldFormatter.headers = this.headers;

@@ -74,4 +74,5 @@ }

const { shouldFormatColumns, headers } = this.checkHeaders(transformedRow);
if (headers) {
if (this.shouldWriteHeaders && headers && !this.hasWrittenHeaders) {
rows.push(this.formatColumns(headers, true));
this.hasWrittenHeaders = true;
}

@@ -89,25 +90,34 @@ if (shouldFormatColumns) {

checkHeaders(row) {
if (!this.parsedHeaders) {
this.parsedHeaders = true;
this.headers = RowFormatter.gatherHeaders(row);
this.fieldFormatter.headers = this.headers;
if (this.headers) {
// either the headers were provided by the user or we have already gathered them.
return { shouldFormatColumns: true, headers: this.headers };
}
if (this.hasWrittenHeaders) {
const headers = RowFormatter.gatherHeaders(row);
this.headers = headers;
this.fieldFormatter.headers = headers;
if (!this.shouldWriteHeaders) {
// if we are not supposed to write the headers then
// alwyas format the columns
return { shouldFormatColumns: true, headers: null };
}
this.hasWrittenHeaders = true;
const shouldFormatColumns = RowFormatter.isHashArray(row) || !Array.isArray(row);
return { shouldFormatColumns, headers: this.headers };
// if the row is equal to headers dont format
return { shouldFormatColumns: !lodash_1.isEqual(headers, row), headers };
}
gatherColumns(row) {
if (this.headers === null) {
throw new Error('Headers is currently null');
}
if (!Array.isArray(row)) {
if (this.headers === null) {
throw new Error('Headers is currently null');
}
return this.headers.map((header) => row[header]);
}
if (RowFormatter.isHashArray(row)) {
return row.map((col) => col[1]);
return this.headers.map((header, i) => {
const col = row[i];
if (col) {
return col[1];
}
return '';
});
}
return row;
return this.headers.map((header, i) => row[i]);
}

@@ -114,0 +124,0 @@ callTransformer(row, cb) {

@@ -29,3 +29,3 @@ import { RowTransformFunction } from './types';

readonly transform: RowTransformFunction | null;
readonly hasProvidedHeaders: boolean;
readonly shouldWriteHeaders: boolean;
readonly escapedQuote: string;

@@ -32,0 +32,0 @@ constructor(opts?: FormatterOptionsArgs);

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

}
this.hasProvidedHeaders = !!this.headers;
this.shouldWriteHeaders = !!this.headers;
this.headers = Array.isArray(this.headers) ? this.headers : null;

@@ -27,0 +27,0 @@ this.escapedQuote = `${this.escape}${this.quote}`;

@@ -17,2 +17,11 @@ # Formatting

* [Alternate `escape`](#examples-alternate-escape)
* [Headers](#examples-headers)
* Auto Discovery
* [Object Rows](#headers-auto-discover-object)
* [Hash Array Rows](#headers-auto-discover-hash-array)
* Provide Headers
* [Array Rows](#headers-provided-array)
* [Hash Array Rows](#headers-provided-hash-array)
* [Object Rows - Reorder Columns](#headers-provided-object)
* [Object Rows - Remove Columns](#headers-provided-object-remove-column)
* [`quoteColumns`](#examples-quote-columns)

@@ -35,5 +44,8 @@ * [`quoteHeaders`](#examples-quote-headers)

* If true then the headers will be auto detected from the first row.
* If the row is an object then the keys will be used.
* If the row is an array of two element arrays (`[ ['header', 'column'], ['header2', 'column2'] ]`) then the first element in each array will be used.
* If the row is a one-dimensional array then headers is a no-op
* If the row is an object then the keys will be used.
* If the row is an array of two element arrays (`[ ['header', 'column'], ['header2', 'column2'] ]`) then the first element in each array will be used.
* If there is not a headers row and you want to provide one then set to a `string[]`
* **NOTE** If the row is an object the headers must match fields in the object, otherwise you will end up with empty fields
* **NOTE** If there are more headers than columns then additional empty columns will be added
* `quoteColumns: {boolean|boolean[]|{[string]: boolean} = false`

@@ -336,2 +348,191 @@ * If `true` then columns and headers will be quoted (unless `quoteHeaders` is specified).

<a name="examples-headers"></a>
### Headers
#### Auto Discovery
`fast-csv` will auto-discover headers when the `headers` option is set to `true`.
**NOTE** When working is one-dimensional array rows (e.g. `[ 'a', 'b', 'c' ]`) this is a no-op.
<a name="headers-auto-discover-object"></a>
[`examples/formatting/headers_auto_discovery_object.example.js`](../examples/formatting/headers_auto_discovery_object.example.js)
In this example the headers are auto-discovered from the objects passed in.
```js
const csvStream = csv.format({ headers: true});
csvStream
.pipe(process.stdout)
.on('end', process.exit);
csvStream.write({ header1: 'value1a', header2: 'value1b' });
csvStream.write({ header1: 'value2a', header2: 'value2b' });
csvStream.write({ header1: 'value3a', header2: 'value3b' });
csvStream.write({ header1: 'value4a', header2: 'value4b' });
csvStream.end();
```
Expected Output:
```
header1,header2
value1a,value1b
value2a,value2b
value3a,value3b
value4a,value4b
```
<a name="headers-auto-discover-hash-array"></a>
[`examples/formatting/headers_auto_discovery_hash_array.example.js`](../examples/formatting/headers_auto_discovery_hash_array.example.js)
In this example the headers are auto-discovered from the hash arrays passed in.
```js
const csvStream = csv.format({ headers: true });
csvStream
.pipe(process.stdout)
.on('end', process.exit);
csvStream.write([ [ 'header1', 'value1a' ], [ 'header2', 'value1b' ] ]);
csvStream.write([ [ 'header1', 'value2a' ], [ 'header2', 'value2b' ] ]);
csvStream.write([ [ 'header1', 'value3a' ], [ 'header2', 'value3b' ] ]);
csvStream.write([ [ 'header1', 'value4a' ], [ 'header2', 'value4b' ] ]);
csvStream.end();
```
Expected Output:
```
header1,header2
value1a,value1b
value2a,value2b
value3a,value3b
value4a,value4b
```
### Provided Headers
You can also provide a set of `headers` by providing an array. This allows you to
* Reorder and/or exclude columns when working when object rows.
* Rename and/or exclude columns when working with hash array rows.
* Specify headers or remove columns when working with array rows.
**NOTE** When working with objects the header names should match keys. The headers option allows you to specify column order.
<a name="headers-provided-array"></a>
[`examples/formatting/headers_provided_array.example.js`](../examples/formatting/headers_provided_array.example.js)
In this example a custom set of headers is provided for rows that are arrays.
```js
const csvStream = csv.format({ headers: [ 'header1', 'header2' ] });
csvStream
.pipe(process.stdout)
.on('end', process.exit);
csvStream.write([ 'value1a', 'value1b' ]);
csvStream.write([ 'value2a', 'value2b' ]);
csvStream.write([ 'value3a', 'value3b' ]);
csvStream.write([ 'value4a', 'value4b' ]);
csvStream.end();
```
Expected Output:
```
header1,header2
value1a,value1b
value2a,value2b
value3a,value3b
value4a,value4b
```
<a name="headers-provided-hash-array"></a>
[`examples/formatting/headers_provided_hash_array.example.js`](../examples/formatting/headers_provided_hash_array.example.js)
In this example the headers are overridden with a custom set of headers
```js
const csvStream = csv.format({ headers: [ 'header1', 'header2' ] });
csvStream
.pipe(process.stdout)
.on('end', process.exit);
csvStream.write([ [ 'h1', 'value1a' ], [ 'h2', 'value1b' ] ]);
csvStream.write([ [ 'h1', 'value2a' ], [ 'h2', 'value2b' ] ]);
csvStream.write([ [ 'h1', 'value3a' ], [ 'h2', 'value3b' ] ]);
csvStream.write([ [ 'h1', 'value4a' ], [ 'h2', 'value4b' ] ]);
csvStream.end();
```
Expected Output:
```
header1,header2
value1a,value1b
value2a,value2b
value3a,value3b
value4a,value4b
```
<a name="headers-provided-object"></a>
[`examples/formatting/headers_provided_object.example.js`](../examples/formatting/headers_provided_object.example.js)
In this example the columns are reordered.
```js
const csvStream = csv.format({ headers: [ 'header2', 'header1' ] });
csvStream
.pipe(process.stdout)
.on('end', process.exit);
csvStream.write({ header1: 'value1a', header2: 'value1b' });
csvStream.write({ header1: 'value2a', header2: 'value2b' });
csvStream.write({ header1: 'value3a', header2: 'value3b' });
csvStream.write({ header1: 'value4a', header2: 'value4b' });
csvStream.end();
```
Expected Output:
```
header2,header1
value1b,value1a
value2b,value2a
value3b,value3a
value4b,value4a
```
<a name="headers-provided-object-remove-column"></a>
[`examples/formatting/headers_provided_object_remove_column.example.js`](../examples/formatting/headers_provided_object_remove_column.example.js)
In this example the one of the columns is removed.
```js
const csvStream = csv.format({ headers: [ 'header2' ] });
csvStream
.pipe(process.stdout)
.on('end', process.exit);
csvStream.write({ header1: 'value1a', header2: 'value1b' });
csvStream.write({ header1: 'value2a', header2: 'value2b' });
csvStream.write({ header1: 'value3a', header2: 'value3b' });
csvStream.write({ header1: 'value4a', header2: 'value4b' });
csvStream.end();
```
Expected Output:
```
header2
value1b
value2b
value3b
value4b
```
<a name="examples-quote-columns"></a>

@@ -338,0 +539,0 @@ ### `quoteColumns`

@@ -0,1 +1,5 @@

# v3.3.0
* [FIXED] First row of CSV is removed when headers array is provided [#252](https://github.com/C2FO/fast-csv/issues/252)
# v3.2.0

@@ -2,0 +6,0 @@

{
"name": "fast-csv",
"version": "3.2.0",
"version": "3.3.0",
"description": "CSV parser and writer",

@@ -5,0 +5,0 @@ "main": "./build/src/index.js",

@@ -1,2 +0,2 @@

import { isFunction } from 'lodash';
import { isFunction, isEqual } from 'lodash';
import { FormatterOptions } from '../FormatterOptions';

@@ -60,3 +60,3 @@ import FieldFormatter from './FieldFormatter';

private parsedHeaders: boolean;
private shouldWriteHeaders: boolean;

@@ -72,6 +72,7 @@ private hasWrittenHeaders: boolean;

this._rowTransform = null;
this.headers = formatterOptions.headers;
this.parsedHeaders = formatterOptions.hasProvidedHeaders && Array.isArray(formatterOptions.headers);
this.hasWrittenHeaders = !formatterOptions.hasProvidedHeaders;
if (this.parsedHeaders && this.headers !== null) {
this.shouldWriteHeaders = formatterOptions.shouldWriteHeaders;
this.hasWrittenHeaders = false;
if (this.headers !== null) {
this.fieldFormatter.headers = this.headers;

@@ -102,4 +103,5 @@ }

const { shouldFormatColumns, headers } = this.checkHeaders(transformedRow);
if (headers) {
if (this.shouldWriteHeaders && headers && !this.hasWrittenHeaders) {
rows.push(this.formatColumns(headers, true));
this.hasWrittenHeaders = true;
}

@@ -118,26 +120,36 @@ if (shouldFormatColumns) {

private checkHeaders(row: Row): { headers?: string[] | null; shouldFormatColumns: boolean } {
if (!this.parsedHeaders) {
this.parsedHeaders = true;
this.headers = RowFormatter.gatherHeaders(row);
this.fieldFormatter.headers = this.headers;
if (this.headers) {
// either the headers were provided by the user or we have already gathered them.
return { shouldFormatColumns: true, headers: this.headers };
}
if (this.hasWrittenHeaders) {
const headers = RowFormatter.gatherHeaders(row);
this.headers = headers;
this.fieldFormatter.headers = headers;
if (!this.shouldWriteHeaders) {
// if we are not supposed to write the headers then
// alwyas format the columns
return { shouldFormatColumns: true, headers: null };
}
this.hasWrittenHeaders = true;
const shouldFormatColumns = RowFormatter.isHashArray(row) || !Array.isArray(row);
return { shouldFormatColumns, headers: this.headers };
// if the row is equal to headers dont format
return { shouldFormatColumns: !isEqual(headers, row), headers };
}
private gatherColumns(row: Row): string[] {
if (this.headers === null) {
throw new Error('Headers is currently null');
}
if (!Array.isArray(row)) {
if (this.headers === null) {
throw new Error('Headers is currently null');
}
return this.headers.map((header): string => row[header]);
}
if (RowFormatter.isHashArray(row)) {
return row.map((col): string => col[1]);
return this.headers.map((header, i): string => {
const col = row[i];
if (col) {
return col[1];
}
return '';
});
}
return row;
return this.headers.map((header, i): string => row[i]);
}

@@ -144,0 +156,0 @@

@@ -43,3 +43,3 @@ import { RowTransformFunction } from './types';

public readonly hasProvidedHeaders: boolean;
public readonly shouldWriteHeaders: boolean;

@@ -58,3 +58,3 @@ public readonly escapedQuote: string;

}
this.hasProvidedHeaders = !!this.headers;
this.shouldWriteHeaders = !!this.headers;
this.headers = Array.isArray(this.headers) ? this.headers : null;

@@ -61,0 +61,0 @@ this.escapedQuote = `${this.escape}${this.quote}`;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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