New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

csv-types

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

csv-types - npm Package Compare versions

Comparing version 0.2.4 to 0.3.0

18

CHANGELOG.md
# CHANGELOG
## v0.3.0 (2017-11-05)
**Enhancements:**
- Supported custom delimiter, escape and comment characters in options.
- Coverage in branches reach up to 98.6%.
**News:**
- Added ebert analysis online tool.
- Repository promoted to the Group4Layers organization.
- New "minor" version to update the changes.
**Statistics:**
- 42 TDD Tests.
- Code coverage of 98.7%.
## v0.2.4 (2017-11-02)

@@ -4,0 +22,0 @@

2

LICENSE.md

@@ -5,3 +5,3 @@ # LICENSE

Copyright (c) 2017 rNoz <rnoz.commits@gmail.com> (Group4Layers®)
Copyright (c) 2017 nozalr <nozalr@group4layers.com> (Group4Layers®)

@@ -8,0 +8,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

{
"name": "csv-types",
"version": "0.2.4",
"description": "CSV Types (csv-types-js) is a JavaScript library to parse CSV (comma separated values) strings and produce a JavaScript AST (abstract syntax tree) with the data. It also supports types specs: multiple headers-values (tables) per csv string.",
"version": "0.3.0",
"description": "CSV Types (csv-types-js) is a JavaScript library to parse CSV strings (comma separated values and text files with fields delimited by a character) and produce a JavaScript AST (abstract syntax tree) with the data. It also supports *types specs*: multiple headers-values (tables) per csv string.",
"main": "src/index.js",
"module": "src/index.js",
"scripts": {
"test": "./node_modules/mocha/bin/mocha test/mocha.js",
"test-stop": "./node_modules/mocha/bin/mocha --bail test/mocha.js",
"lint": "./node_modules/eslint/bin/eslint.js src",
"coverage": "nyc ./node_modules/mocha/bin/mocha test/mocha.js",
"coveralls": "nyc report --reporter=text-lcov | coveralls",
"coverage-html": "nyc --reporter=html ./node_modules/mocha/bin/mocha test/mocha.js"
"test": "./node_modules/.bin/mocha test/mocha.js",
"test-stop": "./node_modules/.bin/mocha --bail test/mocha.js",
"lint": "./node_modules/.bin/eslint src && echo 'OK Lint'",
"coverage": "./node_modules/.bin/nyc ./node_modules/.bin/mocha test/mocha.js",
"coveralls": "npm run coverage; ./node_modules/.bin/nyc report --reporter=text-lcov | coveralls",
"coverage-check": "./node_modules/.bin/nyc --check-coverage true --lines 95 ./node_modules/.bin/mocha test/mocha.js",
"coverage-html": "./node_modules/.bin/nyc --reporter=html ./node_modules/.bin/mocha test/mocha.js"
},

@@ -20,3 +20,3 @@ "engines": {

"type": "git",
"url": "https://github.com/rNoz/csv-types-js.git"
"url": "https://github.com/Group4Layers/csv-types-js.git"
},

@@ -32,3 +32,3 @@ "keywords": [

],
"author": "rNoz",
"author": "nozalr",
"license": "MIT",

@@ -35,0 +35,0 @@ "devDependencies": {

# CSV Types (csv-types-js)
[![JavaScript](https://img.shields.io/badge/made_in-javascript-fed93d.svg?style=flat-square)](https://developer.mozilla.org/docs/Web/JavaScript) [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://github.com/rNoz/csv-types-js/blob/master/LICENSE.md) [![Coverage](https://img.shields.io/badge/coverage-98.12%25-green.svg)](https://github.com/rNoz/csv-types-js) [![Tests](https://img.shields.io/badge/tests-32%2F32-green.svg)](https://github.com/rNoz/csv-types-js)
[![JavaScript](https://img.shields.io/badge/made_in-javascript-fed93d.svg?style=flat-square)](https://developer.mozilla.org/docs/Web/JavaScript) [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://github.com/Group4Layers/csv-types-js/blob/master/LICENSE.md) [![Coverage](https://img.shields.io/badge/coverage-98.7%25-green.svg)](https://github.com/Group4Layers/csv-types-js) [![Tests](https://img.shields.io/badge/tests-42%2F42-green.svg)](https://github.com/Group4Layers/csv-types-js)
CSV Types (csv-types-js) is a JavaScript library to parse CSV (comma separated values) strings and produce a JavaScript AST (abstract syntax tree) with the data. It also supports *types specs*: multiple headers-values (tables) per csv string.
CSV Types (csv-types-js) is a JavaScript library to parse CSV strings (comma separated values and text files with fields delimited by a character) and produce a JavaScript AST (abstract syntax tree) with the data. It also supports *types specs*: multiple headers-values (tables) per csv string.
It has been tested with `node >= 6`.
Online tools: [![Build Status](https://travis-ci.org/Group4Layers/csv-types-js.svg?branch=master)](https://travis-ci.org/Group4Layers/csv-types-js) [![Coverage Status](https://coveralls.io/repos/github/Group4Layers/csv-types-js/badge.svg?branch=master)](https://coveralls.io/github/Group4Layers/csv-types-js?branch=master) [![Ebert](https://ebertapp.io/github/Group4Layers/csv-types-js.svg)](https://ebertapp.io/github/Group4Layers/csv-types-js)
This library is commonly used with [FlexTable](https://github.com/Group4Layers/flextable) to facilitate the data manipulation produced by CSV Types (the data structure is consumed by FlexTable).
## Table of Contents

@@ -24,3 +26,3 @@

CSV Types (csv-types-js) is a JavaScript library to parse CSV (comma separated values) strings and produce a JavaScript AST (abstract syntax tree) with the data. It also supports *types specs*: multiple headers-values (tables) per csv string.
CSV Types (csv-types-js) is a JavaScript library to parse CSV strings (comma separated values and text files with fields delimited by a character) and produce a JavaScript AST (abstract syntax tree) with the data. It also supports *types specs*: multiple headers-values (tables) per csv string.

@@ -78,2 +80,4 @@ It parses four types of CSV formats, being the first two common between different applications and parsers, but have disadvantages over the last two that we are using in Group4Layers.

This library is commonly used with [FlexTable](https://github.com/Group4Layers/flextable) to facilitate the data manipulation produced by CSV Types (the data structure is consumed by FlexTable).
## Installation

@@ -88,5 +92,7 @@

```sh
npm i "http://github.com/rNoz/csv-types-js.git"
npm i "http://github.com/Group4Layers/csv-types-js.git"
```
It has been tested with `node >= 6`, but it is widely used in Firefox and Chrome with building tools like `webpack`.
## Examples

@@ -96,10 +102,13 @@

The configuration is configured with `CSV.configure()`. It will preserve the configuration between `parse` operations. To reset the configuration use `CSV.configure(null)`. Therefore, the best practice would be to do:
The configuration is set in the constructor `new CSV()` and with the method `lCSV.configure()` when the object is built. Every consequent call to `parse` will use the last options configured (it is overwritten with every `configure` call).
```js
const CSV = require('csv-types');
CSV.configure(null);
CSV.configure(yourOptions); // configure if you need to change the defaults
const CSV = require('csv-types').CSV;
let lCSV = new CSV(yourOptions); // configure if you need to change defaults
// ...
lCSV.configure(yourNewOptions); // reconfigure if you want
```
You can just apply the defaults by doing `configure(null)` or `configure({})` (the same for the constructor).
See the available options for configure in [Options](#options).

@@ -118,4 +127,5 @@

```js
const CSV = require('csv-types');
let results = CSV.parse(`#type-a,col1,col2
const CSV = require('csv-types').CSV;
let results = new CSV({types:true})
.parse(`#type-a,col1,col2
type-a,1,2

@@ -132,4 +142,4 @@ type-a,2,3

hlength: 2,
values: [["1", "2"], ["2", "3"]] },
"b": { headers: ["2"], hlength: 1, values: [["2"]] } }
values: [["1", "2"], ["2", "3"]], vlength: 2 },
"b": { headers: ["2"], hlength: 1, values: [["2"]], vlength: 1 } }
```

@@ -147,7 +157,8 @@

const CSV = require('csv-types');
CSV.configure({ types: false });
let results = CSV.parse(`#type-a,col1,col2
let lCSV = new CSV();
let results = lCSV.parse(`#type-a,col1,col2
type-a,1,2
type-a,2,3`);
```
`results`:

@@ -157,3 +168,3 @@ ```js

hlength: 3,
values: [["type-a", "1", "2"], ["type-a", "2", "3"]] } }
values: [["type-a", "1", "2"], ["type-a", "2", "3"]], vlength: 2 } }
```

@@ -170,5 +181,5 @@

```js
const CSV = require('csv-types');
CSV.configure({ types: false, headers: false });
let results = CSV.parse(`#type-a,col1,col2
const CSV = require('csv-types').CSV;
let lCSV = new CSV({ headers: false });
let results = lCSV.parse(`#type-a,col1,col2
type-a,1,2

@@ -195,6 +206,7 @@ type-a,2,3,4,5`);

```js
const CSV = require('csv-types');
const CSV = require('csv-types').CSV;
CSV.configure({ cast: true, firstLineHeader: true });
let results = CSV.parse(`case,first,second
let lCSV = new CSV();
lCSV.configure({ cast: true, firstLineHeader: true });
let results = lCSV.parse(`case,first,second
type-a,1.01,2

@@ -205,3 +217,3 @@ type-a,2,-3`);

`results`:
```
```js
{ headers: ["case", "first", "second"],

@@ -221,3 +233,3 @@ hlength: 3,

```js
const CSV = require('csv-types');
const CSV = require('csv-types').CSV;

@@ -236,4 +248,3 @@ function castFn(value, isHeader, type, column){

CSV.configure({ types: true, cast: castFn });
let results = CSV.parse(`#type-a,1,2
let results = new CSV({types:true, cast: castFn}).parse(`#type-a,1,2
type-a,1,2

@@ -244,3 +255,3 @@ type-a,2,3`);

`results`:
```
```js
{ "a": { headers: ["the1", "the2"],

@@ -261,3 +272,3 @@ hlength: 2,

```js
const CSV = require('csv-types');
const CSV = require('csv-types').CSV;

@@ -274,4 +285,4 @@ function castFn(value, isHeader, type, column, row){

CSV.configure({ types: false, headers: false, cast: castFn });
let results = CSV.parse(`#type-a,1,2,3
let lCSV = new CSV({ headers: false, cast: castFn });
let results = lCSV.parse(`#type-a,1,2,3
type-a,1,2,tres

@@ -282,3 +293,4 @@ # comment

```
`results`:
```js
{ headers: [],

@@ -290,3 +302,3 @@ hlength: 0,

**Using row function to alter based on postprocessing**
**Using row function to alter based on post-processing**

@@ -304,3 +316,3 @@ ```csv

```js
const CSV = require('csv-types');
const CSV = require('csv-types').CSV;

@@ -319,4 +331,5 @@ function rowFn(array, type, definition, row){

CSV.configure({ row: rowFn });
let results = CSV.parse(`
let lCSV = new CSV({row: rowFn});
lCSV.configure({row: rowFn, types:true}); // options are overwritten
let results = lCSV.parse(`
#type-a,1,2

@@ -331,3 +344,3 @@ type-a,1,2

`results`:
```
```js
{ a: { headers: [ '1', '2' ],

@@ -340,3 +353,3 @@ hlength: 2,

**Using row function to alter based on postprocessing with no types**
**Using row function to alter based on post-processing with no types**

@@ -351,3 +364,3 @@ ```csv

```
```js
function rowFn(array, type, definition, row){

@@ -367,4 +380,4 @@ let sum = 0;

}
CSV.configure({ types: false, headers: false, row: rowFn });
let results = CSV.parse(`
let lCSV = new (require('csv-types')).CSV({ types: false, headers: false, row: rowFn });
let results = lCSV.parse(`
#type-a,b,c,d

@@ -377,3 +390,3 @@ type-a,1,2,3

`results`:
```
```js
{ headers: [], values: [["type-a", 4, 0, -1]], vlength: 1 },

@@ -389,4 +402,6 @@ ```

```
CSV.configure({ fail: function(m){ popup.error(m); return m; } });
```js
const CSV = require('csv-types').CSV;
let lCSV = new CSV();
lCSV.configure({ fail: function(m){ popup.error(m); return m; } });
let results = CSV.parse(`

@@ -398,3 +413,3 @@ #type-a,1,2,3

In this case the `CSV.parse` method would trigger `popup.error(m)` instead of `console.log(m)`.
In this case the `lCSV.parse` method would trigger `popup.error(m)` instead of `console.log(m)`.

@@ -406,2 +421,32 @@ `results`:

**Custom delimiter, escape and comment chars**
```csv
%field;num;str
% comment
`escaped; as you see`;243;string
`escaped`; as you see;243
```
```js
const CSV = require('csv-types').CSV;
let lCSV = new CSV({ delimiter: ';', escape: "`", comment: '%' });
let results = lCSV.parse(`
%field;num;str
% comment
\`escaped; as you see\`;243;string
\`escaped\`; as you see;100
`);
```
`results`:
```js
{ headers: [ 'field', 'num', 'str' ],
hlength: 3,
values:
[ [ 'escaped; as you see', '243', 'string' ],
[ 'escaped', 'as you see', '100' ] ],
vlength: 2 }
```
## Options

@@ -423,8 +468,9 @@

headers: true,
firstNotEmptyLineIsHeader: false,
firstLineHeader: false,
delimiter: ',',
escape: '"',
comment: '#',
cast: false,
row: false,
};
CSV.configure(opts);
```

@@ -440,2 +486,5 @@

| firstLineHeader | bool | headers are in the first not empty line (and not commented) |
| delimiter | char | column character delimiter |
| escape | char | column escape character |
| comment | char | comment char (omits the line) |
| cast | bool/func | cast function for every value (by default false: no casting) |

@@ -446,2 +495,6 @@ | row | bool/func | row function for every row values |

The option `firstLineHeader` only works if `headers` is true.
The option `headers` only works if `types` is false (because types needs headers always).
The cast function receives this parameters:

@@ -452,5 +505,13 @@ - `value` (`any`): the value (after the trimming, if applicable)

- `column` (`int`): the column index starting from 0 (the first)
- `row` (`int`): the row index starting from 0 (the first)
- `row` (`int`): the row index starting from 0 (the first).
The row function receives this parameters:
And the value returned is inserted as the column value.
```js
function cast(value, isHeader, type, column, row){
// the return value is used for this column
}
```
The row function is not called for the headers and it receives this parameters:
- `value` (`any[]`): array of values

@@ -461,2 +522,10 @@ - `type` (`string`): type of the row (receives `''` if no types)

And if `false` is returned, the row is not inserted in `values`.
```js
function row(value, type, definition, row){
// if false is returned, the row is omitted
}
```
The `definition{}` object is:

@@ -474,3 +543,3 @@ ```

Depending on the CSV format different options are needed for `CSV.configure`. It is assumed the default options are applied (`CSV.configure(null)` or first time used this package after importing it).
Depending on the CSV format different options are needed for the `CSV` constructor or the method `configure`.

@@ -485,3 +554,3 @@ Format 1: **Values**

```js
CSV.configure({ headers: false })
lCSV.configure({ headers: false });
```

@@ -497,3 +566,3 @@

```js
CSV.configure({ firstLineHeader: true })
new CSV{ firstLineHeader: true });
```

@@ -510,3 +579,3 @@

Default options.
Default options (`new CSV()`).

@@ -529,3 +598,3 @@ Format 4: **Types specs**: **comments**, **multiple commented headers** and **multiple type of values**.

```js
CSV.configure({ types: true })
lCSV.configure({ types: true });
```

@@ -537,8 +606,8 @@

One of the applications is highly used in different areas of the company, involving benchmarking, analysis and comparisions. We have many systems/apps to be tested, and some of them create charts with data of different nature. After days of executions we ended with thousands of files, often, connected between them. With the application of CSV Types we ended writing CSV files self-contained (different format types in the same file), reducing drastically the amount of them and having a whole execution in the same file.
One of the applications is highly used in different areas of the company, involving benchmarking, analysis and comparisons. We have many systems/apps to be tested, and some of them create charts with data of different nature. After days of executions we ended with thousands of files, often, connected between them. With the application of CSV Types we ended writing CSV files self-contained (different format types in the same file), reducing drastically the amount of them and having a whole execution in the same file.
```csv
#type-bench,bench_ts,name,compilation_opts,use_c1,use_c2,use_c3,max_cs,devices,scheduler_num,scheduler,c1_power,c2_power,c2_power,num_packages,hguided_params,min_pkg_c1,min_pkg_c2,min_pkg_c3,k,program_args,total_time,total_ws,num_packages_launched,lws,gws,joules_cs,joules_cgs,
#type-bench,bench_ts,name,compilation_opts,use_c1,use_c2,use_c3,max_cs,devices,scheduler_num,scheduler,c1_power,c2_power,c2_power,num_packages,hguided_params,min_pkg_c1,min_pkg_c2,min_pkg_c3,k,program_args,total_time,total_ws,num_packages_launched,lws,gws,joules_cs,joules_cgs,rest
type-bench,1498616602,"binomial","-O2",1,0,0,0,"c1",1,"static",1.000000,1.270000,1.000000,80,2409901,40,99,1,2,"40960000 255",235.331238,163840000,1,256,2621440000,45147.984375,50370.000000,
#type-event,bench_ts,event_type,event_id,device,status,package_size,time_offset,index,value,event_info,
#type-event,bench_ts,event_type,event_id,device,status,package_size,time_offset,index,value,event_info,rest
# ...

@@ -553,3 +622,3 @@ type-event,1498617107,"CB_KERNEL_END",159,"C1","NULL",736,66.736061,163833200,0.000000,"",

type-event,1498617107,"CB_KERNEL_END",166,"C1","NULL",640,66.742310,163839040,0.000000,"",
#type-energy,bench_ts,id,time_offset,watts_cs,joules_total_cs,watts_cgs,joules_total_cgs,
#type-energy,bench_ts,id,time_offset,watts_cs,joules_total_cs,watts_cgs,joules_total_cgs,rest
# ...

@@ -584,2 +653,9 @@ type-energy,1498616602,1,0.001046,0.000000,0.000000,107.000000,42.800000,

✓ open escape double quotes fail
✓ open escape single quotes fail (custom escape char)
✓ no header definition works (no types, no headers)
✓ discard comments
✓ discard comments (custom comment char)
✓ use custom delimiter char (; with no headers)
✓ use custom delimiter char (; with one col)
✓ use custom delimiter, escape and comment chars
✓ no header definition fails

@@ -609,5 +685,8 @@ ✓ no header definition fails (no types)

✓ firstLineHeader is true
✓ firstLineHeader only works when headers is true
✓ firstLineHeader is true (with headers)
✓ wrong options are discarded
32 passing (43ms)
42 passing (18ms)
```

@@ -621,3 +700,3 @@

rNoz <rnoz.commits@gmail.com> (Group4Layers®).
nozalr <nozalr@group4layers.com> (Group4Layers®).

@@ -624,0 +703,0 @@ ## ChangeLog

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

let opts = {
};
let defOpts = {
const defOpts = {
fail: function(m){

@@ -17,2 +13,5 @@ console.log(m);

firstLineHeader: false,
delimiter: ',',
escape: '"',
comment: '#',
cast: false,

@@ -22,255 +21,206 @@ row: false,

function configure(cfg){
if (cfg == null){
cfg = defOpts;
class CSV {
constructor(cfg){
this.configure(cfg);
}
for (let o in cfg){
opts[o] = cfg[o];
}
if (typeof opts.fail !== 'function'){
opts.fail = defOpts.fail;
}
if (typeof opts.trim !== 'boolean'){
opts.trim = defOpts.trim;
}
if (typeof opts.trimEscaped !== 'boolean'){
opts.trimEscaped = defOpts.trimEscaped;
}
if (typeof opts.types !== 'boolean'){
opts.types = defOpts.types;
}
if (typeof opts.headers !== 'boolean'){
opts.headers = defOpts.headers;
}
if (typeof opts.firstLineHeader !== 'boolean'){
opts.firstLineHeader = defOpts.firstLineHeader;
}
if (opts.types){
opts.headers = true;
}
if (typeof opts.cast !== 'function'){
if (opts.cast === true){
opts.cast = casters.number;
}else{
opts.cast = false;
configure(cfg){
if (cfg == null){
cfg = {};
}
}
if (typeof opts.row !== 'function'){
opts.row = false;
}
}
configure(null);
const casters = {
number: function(value, isHeader){
let ret = value;
if (!isHeader){
if (/^[-+]?[\d.]+$/.test(value)){
ret = Number(value);
for (let opt in defOpts){
let value = cfg[opt];
this['_' + opt] = value != null ? value : defOpts[opt];
}
if (typeof this._fail !== 'function'){
this._fail = defOpts.fail;
}
if (typeof this._trim !== 'boolean'){
this._trim = defOpts.trim;
}
if (typeof this._trimEscaped !== 'boolean'){
this._trimEscaped = defOpts.trimEscaped;
}
if (typeof this._types !== 'boolean'){
this._types = defOpts.types;
}
if (typeof this._headers !== 'boolean'){
this._headers = defOpts.headers;
}
if (typeof this._firstLineHeader !== 'boolean'){
this._firstLineHeader = defOpts.firstLineHeader;
}
if (typeof this._delimiter !== 'string' || this._delimiter.length !== 1){
this._delimiter = defOpts.delimiter;
}
if (typeof this._escape !== 'string' || this._escape.length !== 1){
this._escape = defOpts.escape;
}
if (typeof this._comment !== 'string' || this._comment.length !== 1){
this._comment = defOpts.comment;
}
if (this._types){
this._headers = true;
}
if (!this._headers){
this._firstLineHeader = false;
}
if (typeof this._cast !== 'function'){
if (this._cast === true){
this._cast = casters.number;
}else{
this._cast = false;
}
}
return ret;
if (typeof this._row !== 'function'){
this._row = false;
}
}
};
parse(str){
let types = {};
function parse(str){
let types = {};
let lDefType = null;
let lDefType = null;
let lTyped = false; // if the row got the type
let lType = null;
let lArray = null;
let lArrayLen = 0;
let lStr = null;
let lEsc = false; // if has escape double quote ""
let lEscOpen = false;
let lValues = 0; // rows in values
let lTyped = false; // if the row got the type
let lType = null;
let lArray = null;
let lArrayLen = 0;
let lStr = null;
let lDQuoted = false; // if has escape double quote ""
let lDQuotedOpen = false;
let lValues = 0; // rows in values
let line = 1;
let lineI = 0;
let line = 1;
let lineI = 0;
let lastNL = null; // append a last newline when EOF, to append last locals/tmp
let lastNL = null; // append a last newline when EOF, to append last locals/tmp
const optTypes = this._types;
const optHeaders = this._headers;
let headerParsed = false; // only for optTypes == false
const optCast = this._cast;
const optRow = this._row;
const optDel = this._delimiter;
const optEsc = this._escape;
const optComm = this._comment;
let optTypes = opts.types;
let optHeaders = opts.headers;
let headerParsed = false; // only for optTypes == false
let optCast = opts.cast;
let optRow = opts.row;
let optFirstHeader = this._firstLineHeader;
let optFirstHeader = opts.firstLineHeader;
// if (opts.firstLineHeader){
// // str = '#' + str.trim();
// str = '#' + str;
// }
let i = 0;
let cont = true;
let state = 0;
while(cont){
let char = str[i];
if (lastNL) {
char = lastNL;
lastNL = false; // finish
}
if (char){
// DEBUG: console.log(`${i} ${state}: '${char}'`)
switch(state){
case 0: // read
if (char === '#'){
if (optTypes && str.substr(i, 6) === '#type-'){
state = 1; // header
i += 5;
lType = '';
lStr = '';
} else if (!optTypes && !headerParsed) {
state = 1;
lType = '';
lTyped = true;
lArray = [];
lArrayLen = 0;
lStr = '';
}else{
state = 3; // omit until EOL
}
}else if (char === ' ' || char === '\t'){ // omit
}else if (char === '\n'){ // omit
line++;
lineI = i + 1;
}else if (optTypes && char === 't'){
if (str.substr(i, 5) === 'type-'){
state = 2; // value
i += 4;
lType = '';
lStr = '';
}else{
return opts.fail(`invalid row value in line ${line}:\n${str.substr(lineI, i - lineI + 1)}`);
}
}else if (!optTypes && headerParsed){
state = 2; // value
lType = '';
lTyped = true;
lArray = [];
lArrayLen = 0;
lDefType = types[''];
lStr = char;
}else if (!optTypes && optFirstHeader){
state = 1;
lType = '';
lTyped = true;
lArray = [];
lArrayLen = 0;
lStr = char;
}else if (!optTypes && !headerParsed){
return opts.fail(`invalid row (no header definition) in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
}
break;
case 1: // header
if (char === '\n' || char === ','){
if (lStr === ''){
return opts.fail(`invalid header '${lStr}' in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
}else{
if (lTyped){
let value = lStr.trim();
lArray.push(optCast ? optCast(value, true, lType, lArrayLen) : value);
lArrayLen++;
}else{
lType = lStr;
let i = 0;
let cont = true;
let state = 0;
while(cont){
let char = str[i];
if (lastNL) {
char = lastNL;
lastNL = false; // finish
}
if (char){
// uncomment for debug:
// console.log(`${i} ${state}: '${char}'`)
switch(state){
case 0: // read
if (char === optComm){
if (optTypes && str.substr(i+1, 5) === 'type-'){
state = 1; // header
i += 5;
lType = '';
lStr = '';
} else if (!optTypes && !headerParsed) {
state = 1;
lType = '';
lTyped = true;
lStr = '';
lArray = [];
lArrayLen = 0;
lStr = '';
}else{
state = 3; // omit until EOL
}
}
if (char === ','){
lStr = '';
}else if (char === '\n'){
if (types[lType]){
return opts.fail(`previous header definition for '${lType}' in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
}else if (char === ' ' || char === '\t'){ // omit
}else if (char === '\n'){ // omit
line++;
lineI = i + 1;
}else if (optTypes && char === 't'){
if (str.substr(i, 5) === 'type-'){
state = 2; // value
i += 4;
lType = '';
lStr = '';
}else{
return this._fail(`invalid row value in line ${line}:\n${str.substr(lineI, i - lineI + 1)}`);
}
if (!optHeaders){
}else{ // previously: else if (!optTypes)
if (char === optEsc){
lEsc = true;
lEscOpen = true;
// i++;
}else if (headerParsed){
state = 2; // value
lType = '';
lTyped = true;
lArray = [];
lArrayLen = 0;
lDefType = types[''];
lStr = char;
}else if (optFirstHeader){
state = 1;
lType = '';
lTyped = true;
lArray = [];
lArrayLen = 0;
lStr = char;
}else if (!optHeaders){
state = 2; // value
lType = '';
lTyped = true;
lArray = [];
lArrayLen = 0;
if (lDefType == null){
lDefType = types[''] = {
headers: [],
hlength: 0,
values: [],
vlength: 0,
};
}
lStr = char;
}else{ // previously: else if (!headerParsed)
return this._fail(`invalid row (no header definition) in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
}
types[lType] = {
headers: lArray,
hlength: lArrayLen,
values: [],
vlength: 0,
};
lValues = 0;
lType = null;
lArray = null;
lArrayLen = 0;
lStr = null;
lTyped = false;
state = 0;
line++;
lineI = i + 1;
if (!optTypes){
headerParsed = true;
}
}
}else{
lStr += char;
}
break;
case 2: // value
if (char === '\n' || char === ',' || char === '"'){
if (lDQuotedOpen){
if (char === ','){
lStr += char;
}else if (char === '"'){
lDQuotedOpen = false;
}else if (char === '\n'){
return opts.fail(`invalid row with open escaped double quote and reach EOL in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
}
}else{
if (lTyped){
let value = lStr;
if (lDQuoted){
if (opts.trimEscaped){
value = lStr.trim();
}
}else if (opts.trim){
value = lStr.trim();
}
lArray.push(optCast ? optCast(value, false, lType, lArrayLen, lValues) : value);
lArrayLen++;
lDQuoted = false;
lDQuotedOpen = false;
break;
case 1: // header
if (char === '\n' || char === optDel){
if (lStr === ''){
return this._fail(`invalid header '${lStr}' in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
}else{
if (optTypes){ // can !optTypes come here?
lDefType = types[lStr];
// lDefType = types[''];
if (lTyped){
let value = lStr.trim();
lArray.push(optCast ? optCast(value, true, lType, lArrayLen, 0) : value);
lArrayLen++;
}else{
lType = lStr;
lTyped = true;
lStr = '';
lArray = [];
lArrayLen = 0;
}
if (!lDefType){
return opts.fail(`invalid type (no header definition) '${lStr}' in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
}
lType = lStr;
lTyped = true;
lStr = '';
lArray = [];
lArrayLen = 0;
lDQuoted = false;
lDQuotedOpen = false;
}
if (char === ','){
if (char === optDel){
lStr = '';
if (str[i+1] === '"'){
lDQuoted = true;
lDQuotedOpen = true;
i++;
}else{ // previously: else if (char === '\n'){
if (types[lType]){
return this._fail(`previous header definition for '${lType}' in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
}
}else if (char === '\n'){
if (optHeaders && lDefType.hlength !== lArrayLen){
return opts.fail(`invalid row length ${lArrayLen} (header length ${lDefType.hlength}) in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
if (!optHeaders){
lArrayLen = 0;
lArray = [];
}
let insert = optRow ? optRow(lArray, lType, lDefType, lValues) !== false : true;
if (insert){
lDefType.values.push(lArray);
lValues++;
lDefType.vlength++;
}
types[lType] = {
headers: lArray,
hlength: lArrayLen,
values: [],
vlength: 0,
};
lValues = 0;
lType = null;

@@ -281,48 +231,135 @@ lArray = null;

lTyped = false;
lDQuoted = false;
lDQuotedOpen = false;
state = 0;
line++;
lineI = i + 1;
if (!optTypes){
headerParsed = true;
}
}
}else{
lStr += char;
}
}else{
if (lDQuotedOpen){
if (char === '\\' && str[i+1] === '"'){
char = '"';
i++; // omit next
break;
case 2: // value
if (char === '\n' || char === optDel || char === optEsc){
if (lEscOpen){
if (char === optDel){
lStr += char;
}else if (char === optEsc){
lEscOpen = false;
}else{ // previously: else if (char === '\n')
return this._fail(`invalid row with open escaped char ${optEsc} and reach EOL in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
}
}else{
if (lTyped){
let value = lStr;
if (lEsc){
if (this._trimEscaped){
value = lStr.trim();
}
}else if (this._trim){
value = lStr.trim();
}
lArray.push(optCast ? optCast(value, false, lType, lArrayLen, lValues) : value);
lArrayLen++;
lEsc = false;
lEscOpen = false;
}else{
if (optTypes){ // can !optTypes come here?
lDefType = types[lStr];
// lDefType = types[''];
}
if (!lDefType){
return this._fail(`invalid type (no header definition) '${lStr}' in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
}
lType = lStr;
lTyped = true;
lStr = '';
lArray = [];
lArrayLen = 0;
lEsc = false;
lEscOpen = false;
}
if (char === optDel){
lStr = '';
if (str[i+1] === optEsc){
lEsc = true;
lEscOpen = true;
i++;
}
}else{ // previously: else if (char === '\n'){
if (optHeaders && lDefType.hlength !== lArrayLen){
return this._fail(`invalid row length ${lArrayLen} (header length ${lDefType.hlength}) in line ${line} col ${i - lineI + 1}:\n${str.substr(lineI, i - lineI + 1)}`);
}
let insert = optRow ? optRow(lArray, lType, lDefType, lValues) !== false : true;
if (insert){
lDefType.values.push(lArray);
lValues++;
lDefType.vlength++;
}
lType = null;
lArray = null;
lArrayLen = 0;
lStr = null;
lTyped = false;
lEsc = false;
lEscOpen = false;
state = 0;
line++;
lineI = i + 1;
}
}
}else{
if (lEscOpen){
if (char === '\\' && str[i+1] === optEsc){
char = optEsc;
i++; // omit next
}
}
lStr += char;
}
lStr += char;
break;
case 3: // next until EOL
if (char === '\n'){
state = 0;
}
break;
}
break;
case 3: // next until EOL
if (char === '\n'){
state = 0;
}else{ // EOF
if (lastNL == null){ // avoid problems when EOF is in the last row (no next line)
lastNL = '\n';
i = i - 1;
}else{ // now can exit
cont = false;
}
break;
}
}else{ // EOF
if (lastNL == null){ // avoid problems when EOF is in the last row (no next line)
lastNL = '\n';
i = i - 1;
}else{ // now can exit
cont = false;
}
i++;
}
i++;
if (!optTypes){
types = types[''];
}
return types;
}
}
if (!optTypes){
types = types[''];
const casters = {
number: function(value, isHeader){
let ret = value;
if (!isHeader){
if (/^[-+]?[\d.]+$/.test(value)){
ret = Number(value);
}
}
return ret;
}
};
return types;
}
module.exports = {
version: { major: 0, minor: 2, patch: 4 },
parse,
configure,
casters,
version: { major: 0, minor: 3, patch: 0 },
CSV,
casters
};
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