csv42
Convert CSV to JSON and JSON to CSV
Features
- 2 way: convert from and to CSV
- Simple: straightforward and flexible API
- Lightweight: <2KB gzipped with everything included, <1KB gzipped when only using
json2csv
- Fast: faster than the popular CSV libraries out there. See benchmark.
- Modular: only load what you use, thanks to ES5 modules and a plugin architecture
- Powerful:
- Configurable properties:
header
, delimiter
, eol
- Configurable
fields
, with custom value getters and setters and the ability to ignore fields - Configurable serialization and deserialization of values via
formatValue
and parseValue
- Support for nested JSON objects: either flatten nested contents, or stringify as a JSON object
- Standards compliant: adheres to the CSV standard RFC 4180
- Universal: Created for the browser, but can be used in any JavaScript environment like node.js.
Note that the parser has no streaming support.
Why?
Well, you have to write a CSV parser at least once in you life, right? ;)
The csv42
library was developed specifically for https://jsoneditoronline.org. The library was developed for the browser. Besides being small and fast, one important feature is supporting nested JSON objects. So, why the name csv42
? Just because 42 is a beautiful number and reminds us that there is a whole universe of beautiful CSV libraries out there.
Install
npm install csv42
Usage
Install the library once:
Convert JSON to CSV
import { json2csv } from 'csv42'
const users = [
{ id: 1, name: 'Joe', address: { city: 'New York', street: '1st Ave' } },
{ id: 2, name: 'Sarah', address: { city: 'Manhattan', street: 'Spring street' } }
]
const csv = json2csv(users)
console.log(csv)
const csvFlat = json2csv(users, { flatten: false })
console.log(csvFlat)
const csvCustom = json2csv(users, {
fields: [
{ name: 'name', getValue: (object) => object.name },
{ name: 'address', getValue: (object) => object.address.city + ' - ' + object.address.street }
]
})
console.log(csvCustom)
Convert CSV to JSON
import { csv2json } from 'csv42'
const csv = `id,name,address.city,address.street
1,Joe,New York,1st Ave
2,Sarah,Manhattan,Spring street`
const users = csv2json(csv)
console.log(users)
const usersFlat = csv2json(csv, { nested: false })
console.log(usersFlat)
const usersCustom = csv2json(csv, {
fields: [
{ name: 'name', setValue: (object, value) => (object.name = value) },
{ name: 'address.city', setValue: (object, value) => (object.city = value) }
]
})
console.log(usersCustom)
API
json2csv(json: NestedObject[], options?: CsvOptions) : string
Where options
is an object with the following properties:
Option | Type | Description |
---|
header | boolean | If true, a header will be created as first line of the CSV. |
delimiter | string | Default delimiter is , . A delimiter must be a single character. |
eol | \r\n or \n | End of line, can be \r\n (default) or \n . |
flatten | boolean or (value: unknown) => boolean | If true (default), nested objects and arrays will be flattened in multiple CSV columns. When false , nested objects and arrays will be serialized as JSON in a single CSV field. This behavior can be customized by providing your own callback function for flatten . For example, to flatten objects but not arrays, you can do json2csv(json, { flatten: (value) => value ? value.constructor === Object : false }) . The option flatten is not applicable when fields is defined. |
fields | CsvField[] or CsvFieldsParser | A list with fields to be put into the CSV file. This allows specifying the order of the fields and which fields to include/excluded. |
formatValue | ValueFormatter | Function used to change any type of value into a serialized string for the CSV. The build in formatter will only enclose values in quotes when necessary, and will stringify nested JSON objects. |
A simple example of a ValueFormatter
is the following. This formatter will enclose every value in quotes:
function formatValue(value: unknown): string {
return '"' + String(value) + '"'
}
csv2json(csv: string, options?: JsonOptions) : NestedObject[]
Where options
is an object with the following properties:
Option | Type | Description |
---|
header | boolean | Should be set true when the first line of the CSV file contains a header |
delimiter | string | Default delimiter is , . A delimiter must be a single character. |
nested | boolean | If true (default), field names containing a dot will be parsed into nested JSON objects. The option nested is not applicable when fields is defined. |
fields | JsonField[] or JsonFieldsParser | A list with fields to be extracted from the CSV file into JSON. This allows specifying which fields are include/excluded, and how they will be put into the JSON object. A field can be specified either by name, like { name, setValue } , or by the index of the columns in the CSV file, like { index, setValue } . |
parseValue | ValueParser | Used to parse a stringified value into a value again (number, boolean, string, ...). The build in parser will parse numbers and booleans, and will parse stringified JSON objects. |
A simple value parser can look as follows. This will keep all values as string:
function parseValue(value: string): unknown {
return value.startsWith('"') ? value.substring(1, value.length - 1).replaceAll('""', '"') : value
}
Utility functions
The library exports a number of utility functions:
Function | Description |
---|
createFormatValue(delimiter: string): (value: unknown) => string | Create a function that can format (stringify) a value into a valid CSV value, escaping the value when needed. This function is used as default for the option formatValue . |
parseValue(value: string): unknown | Parse a string into a value, parse numbers into a number, etc. This is the function used by default for the option parseValue . |
collectNestedPaths(records: NestedObject[], recurse: boolean): Path[] | Loop over the data and collect all nested paths. This can be used to generate a list with fields. |
parsePath(pathStr: string): Path | Parse a path like 'items[3].name' |
function stringifyPath(path: Path): string | Stringify a path into a string like 'items[3].name' |
getIn(object: NestedObject, path: Path): unknown | Get a nested property from an object |
setIn(object: NestedObject, path: Path, value: unknown): NestedObject | Set a nested property in an object |
Alternatives
Release
To release a new version:
$ npm run release
This will:
- lint
- test
- build
- increment the version number
- push the changes to git, add a git version tag
- publish the npm package
To try the build and see the change list without actually publishing:
$ npm run release-dry-run
License
csv42
is released as open source under the permissive the ISC license.
If you are using csv42
commercially, there is a social (but no legal) expectation that you help fund its maintenance. Start here.