csv-to-js-parser
Advanced tools
Comparing version 2.2.3 to 2.3.0
338
app.js
@@ -28,3 +28,3 @@ /* | ||
{ | ||
if (typeof data !== 'string' || | ||
if (typeof data !== 'string' || | ||
(typeof param1 === 'object' && typeof param2 === 'object') || | ||
@@ -34,3 +34,5 @@ (typeof param1 === 'string' && typeof param2 === 'string') || | ||
(param2 && (typeof param2 !== 'object' && typeof param2 !== 'string'))) | ||
{ | ||
throw new Error('Incorrect parameters'); | ||
} | ||
@@ -47,7 +49,6 @@ let description; | ||
} | ||
else | ||
else | ||
{ | ||
description = param1; | ||
} | ||
} | ||
@@ -69,19 +70,6 @@ if (param2) | ||
//Spliting data by rows | ||
{ | ||
//Checking row delimeter | ||
let newRow; | ||
let i = data.indexOf('\n', 0); | ||
if (i === -1) throw new Error('No row delimeter found'); | ||
newRow = (data[i - 1] === '\r') ? '\r\n' : '\n'; | ||
data = data.split(newRow); | ||
//Deleting last empty row | ||
i = data.length - 1; | ||
while (data[i] === '') | ||
{ | ||
data.pop(); | ||
i--; | ||
} | ||
} | ||
let header = data[0].split(delimeter); | ||
const dataSplited = splitTiaQuotes(data, delimeter); | ||
let header = dataSplited[0]; | ||
data = dataSplited[1]; | ||
//Making default description | ||
@@ -93,24 +81,6 @@ if (!description) | ||
{ | ||
description[key] = {type: 'string', group: 1}; | ||
description[key] = { type: 'string', group: 1 }; | ||
} | ||
} | ||
/* | ||
console.log(delimeter); | ||
console.log(description); | ||
*/ | ||
//Deleting header from data | ||
data.shift(); | ||
//Spliting data by delimeter | ||
{ | ||
let newData = []; | ||
for (let row of data) | ||
{ | ||
let arr = row.split(delimeter); | ||
newData.push(arr); | ||
} | ||
data = newData; | ||
} | ||
let constantsIndexes = {}; | ||
@@ -123,3 +93,3 @@ let constantOrder = []; | ||
{ | ||
let index = header.indexOf(key, 0); | ||
let index = header.indexOf(key, 0); | ||
if (index === -1) throw new Error('Cannnot find selected fields in the header'); | ||
@@ -130,3 +100,3 @@ if (Number(description[key].group) > 0) | ||
constantsIndexes[key] = index; | ||
constantOrder.push({group: description[key].group, key: key}); | ||
constantOrder.push({ group: description[key].group, key: key }); | ||
} | ||
@@ -154,3 +124,3 @@ else | ||
return compare(a, b); | ||
} | ||
}; | ||
} | ||
@@ -213,3 +183,3 @@ //Sorting constantOrder | ||
let out = []; | ||
if (Object.keys(arraysIndexes).length) //If we have not group columns then we need create arrays in every object. Else we need put equal rows to separate objects. | ||
@@ -220,3 +190,3 @@ { | ||
let obj = {}; | ||
for (let key in constantsIndexes) | ||
for (let key in constantsIndexes) | ||
{ | ||
@@ -248,3 +218,3 @@ let value = data[i][0][constantsIndexes[key]]; | ||
let obj = {}; | ||
for (let key in constantsIndexes) | ||
for (let key in constantsIndexes) | ||
{ | ||
@@ -260,45 +230,232 @@ let value = data[i][j][constantsIndexes[key]]; | ||
/* | ||
function typeInitialisation(type) | ||
function convertToType(value, type) | ||
{ | ||
if (value === '') return null; | ||
switch(type.toLowerCase()) | ||
{ | ||
case 'string': | ||
return ''; | ||
case 'number': | ||
return 0; | ||
case 'boolean': | ||
case 'string': | ||
return String(value); | ||
case 'number': | ||
return Number(value); | ||
case 'boolean': | ||
{ | ||
let val = value.toLowerCase(); | ||
if (val === 'true') | ||
{ | ||
return true; | ||
} | ||
else if(val === 'false') | ||
{ | ||
return false; | ||
default: | ||
throw new Error('Type is incorrect'); | ||
} | ||
else | ||
{ | ||
throw new Error('Cannont convert boolean value'); | ||
} | ||
} | ||
default: | ||
throw new Error('Type is incorrect'); | ||
} | ||
} | ||
*/ | ||
function convertToType(value, type) | ||
//Split by delimeter, taking into account double quotes according to rfc4180 | ||
function splitTiaQuotes(data, delimeter) | ||
{ | ||
if (value === '') return null; | ||
switch(type.toLowerCase()) | ||
const dataArray = []; | ||
let header = null; | ||
let rowArray = []; | ||
let dataIndex = 0; | ||
let qPlaceOpen = 0; | ||
let dOrnPlace = 0; | ||
let dPlace = 0; | ||
let rnPlace = 0; | ||
let qPlaceClosed = -1; | ||
let hasNotSpaceSimbolAfterClosingQuotes; | ||
for (;;) | ||
{ | ||
case 'string': | ||
return String(value); | ||
case 'number': | ||
return Number(value); | ||
case 'boolean': | ||
let val = value.toLowerCase(); | ||
if (val === "true") | ||
if (dPlace >= 0 && dPlace <= dOrnPlace) dPlace = data.indexOf(delimeter, dataIndex); | ||
if (rnPlace >= 0 && rnPlace <= dOrnPlace) rnPlace = data.indexOf('\n', dataIndex); | ||
set_dOrnPlace(); | ||
if (qPlaceOpen !== -1 && ((dOrnPlace >= 0 && qPlaceOpen <= dOrnPlace) || dOrnPlace === -1)) | ||
{ | ||
qPlaceOpen = data.indexOf('"', dataIndex); | ||
qPlaceClosed = qPlaceOpen === -1 ? -1 : data.indexOf('"', qPlaceOpen + 1); | ||
} | ||
if (dOrnPlace === -1) //last field | ||
{ | ||
if (qPlaceOpen === -1) //last field without quotes | ||
{ | ||
return true; | ||
rowArray.push(data.slice(dataIndex, data.length)); | ||
addRowToArray(); | ||
break; | ||
} | ||
else if(val === "false") | ||
else if(qPlaceClosed > qPlaceOpen) //last field has more then one quotes | ||
{ | ||
return false; | ||
while (data[qPlaceClosed + 1] === '"') //qPlaceClosed refer to escape simbol of " | ||
{ | ||
qPlaceClosed = data.indexOf('"', qPlaceClosed + 2); | ||
} | ||
hasNotSpaceSimbolAfterClosingQuotes = false; | ||
for (let i = qPlaceClosed + 1; i < data.length; i++) //After closing quotes and before delimeter we have not space simbols | ||
{ | ||
if (data[i] !== ' ') | ||
{ | ||
hasNotSpaceSimbolAfterClosingQuotes = true; | ||
break; | ||
} | ||
} | ||
if (hasNotSpaceSimbolAfterClosingQuotes) | ||
{ | ||
rowArray.push(data.slice(dataIndex, data.length)); | ||
} | ||
else | ||
{ | ||
rowArray.push(data.slice(qPlaceOpen + 1, qPlaceClosed).replace(/""/g, '"')); | ||
} | ||
addRowToArray(); | ||
break; | ||
} | ||
else //last field has only one qoute | ||
{ | ||
rowArray.push(data.slice(dataIndex, data.length)); | ||
addRowToArray(); | ||
break; | ||
} | ||
} | ||
else if (qPlaceOpen === -1) //no quotes in field; | ||
{ | ||
addFieldWithNoQuotes(); | ||
dataIndex = dOrnPlace + 1; | ||
addRowToArray(); | ||
} | ||
else if (qPlaceOpen < dOrnPlace) //field has quotes | ||
{ | ||
let fieldStartsFromQuote; | ||
if (qPlaceOpen === dataIndex) | ||
{ | ||
fieldStartsFromQuote = true; | ||
} | ||
else | ||
{ | ||
throw new Error('Cannont convert boolean value'); | ||
}; | ||
default: | ||
throw new Error('Type is incorrect'); | ||
fieldStartsFromQuote = true; | ||
for (let i = dataIndex; i < qPlaceOpen; i++) | ||
{ | ||
if (data[i] !== ' ') | ||
{ | ||
fieldStartsFromQuote = false; | ||
break; | ||
} | ||
} | ||
} | ||
if (fieldStartsFromQuote) //filed start from quote | ||
{ | ||
for (;;) | ||
{ | ||
if (data[qPlaceClosed + 1] === '"') //qPlaceClosed refer to escape simbol of " | ||
{ | ||
qPlaceClosed = data.indexOf('"', qPlaceClosed + 2); | ||
} | ||
else | ||
{ | ||
if (dOrnPlace < qPlaceClosed) //dOrnPlace refer to delimeter into escaped filed, for example ""aa, aa | ||
{ | ||
if (dPlace < qPlaceClosed) dPlace = data.indexOf(delimeter, qPlaceClosed + 1); | ||
if (rnPlace < qPlaceClosed) rnPlace = data.indexOf('\n', qPlaceClosed + 1); | ||
set_dOrnPlace(); | ||
} | ||
break; | ||
} | ||
} | ||
hasNotSpaceSimbolAfterClosingQuotes = false; | ||
for (let i = qPlaceClosed + 1; i < dOrnPlace; i++) //After closing quotes and before delimeter we have not space simbols | ||
{ | ||
let s = data[i]; | ||
if (!(s === ' ' || s === '\r')) | ||
{ | ||
hasNotSpaceSimbolAfterClosingQuotes = true; | ||
break; | ||
} | ||
} | ||
if (hasNotSpaceSimbolAfterClosingQuotes) | ||
{ | ||
rowArray.push(data.slice(dataIndex, dOrnPlace)); | ||
} | ||
else | ||
{ | ||
rowArray.push(data.slice(qPlaceOpen + 1, qPlaceClosed).replace(/""/g, '"')); | ||
} | ||
dataIndex = dOrnPlace + 1; | ||
addRowToArray(); | ||
} | ||
else //filed has quote, but not start from quote | ||
{ | ||
addFieldWithNoQuotes(); | ||
dataIndex = dOrnPlace + 1; | ||
addRowToArray(); | ||
} | ||
} | ||
else //filed has not quotes | ||
{ | ||
addFieldWithNoQuotes(); | ||
dataIndex = dOrnPlace + 1; | ||
addRowToArray(); | ||
} | ||
} | ||
//Deleting last empty rows | ||
{ | ||
let i = dataArray.length - 1; | ||
while (dataArray[i].length === 1 && dataArray[i][0] === '') | ||
{ | ||
dataArray.pop(); | ||
i--; | ||
} | ||
} | ||
return [header, dataArray]; | ||
function addFieldWithNoQuotes() | ||
{ | ||
if (dOrnPlace === rnPlace && data[dOrnPlace - 1] === '\r') | ||
{ | ||
rowArray.push(data.slice(dataIndex, dOrnPlace - 1)); | ||
} | ||
else | ||
{ | ||
rowArray.push(data.slice(dataIndex, dOrnPlace)); | ||
} | ||
} | ||
function addRowToArray() | ||
{ | ||
if (dOrnPlace === rnPlace) | ||
{ | ||
if (header === null) | ||
{ | ||
header = rowArray; | ||
} | ||
else | ||
{ | ||
dataArray.push(rowArray); | ||
} | ||
rowArray = []; | ||
} | ||
} | ||
function set_dOrnPlace() | ||
{ | ||
if (dPlace === -1) | ||
{ | ||
dOrnPlace = rnPlace; | ||
} | ||
else if (rnPlace === -1) | ||
{ | ||
dOrnPlace = dPlace; | ||
} | ||
else if (rnPlace < dPlace) | ||
{ | ||
dOrnPlace = rnPlace; | ||
} | ||
else | ||
{ | ||
dOrnPlace = dPlace; | ||
} | ||
} | ||
} | ||
@@ -309,3 +466,3 @@ }; | ||
{ | ||
if (!Array.isArray(obj)) throw new Error ('Object is not array'); | ||
if (!Array.isArray(obj)) throw new Error('Object is not array'); | ||
if (!obj[0]) throw new Error('Object error'); | ||
@@ -331,3 +488,3 @@ if (!delimeter) delimeter = ','; | ||
{ | ||
out += keys[i]; | ||
out += needQuotesCheck(keys[i].toString()); | ||
if (i !== keys.length - 1) out += delimeter; | ||
@@ -347,3 +504,3 @@ isConstant[i] = !Array.isArray(obj[0][keys[i]]); | ||
let ln = elem[keys[i]].length; | ||
if (maxArrayLength < ln) maxArrayLength = ln; | ||
if (maxArrayLength < ln) maxArrayLength = ln; | ||
} | ||
@@ -361,3 +518,3 @@ } | ||
let val = elem[keys[j]]; | ||
if (val !== null) out += val.toString(); | ||
if (val !== null) out += needQuotesCheck(val.toString()); | ||
} | ||
@@ -367,3 +524,3 @@ else | ||
let val = elem[keys[j]][i]; | ||
if (val !== null) out += val.toString(); | ||
if (val !== null) out += needQuotesCheck(val.toString()); | ||
} | ||
@@ -380,3 +537,3 @@ if (j !== keys.length - 1) out += delimeter; | ||
let val = elem[keys[i]]; | ||
if (val !== null) out += val.toString(); | ||
if (val !== null) out += needQuotesCheck(val.toString()); | ||
if (i !== keys.length - 1) out += delimeter; | ||
@@ -388,2 +545,15 @@ } | ||
return out; | ||
function needQuotesCheck(val) | ||
{ | ||
if (val.indexOf('"') === -1) | ||
{ | ||
if (val.indexOf(delimeter) === -1 && val.indexOf('\n') === -1) return val; | ||
} | ||
else | ||
{ | ||
val = val.replace(/"/g, '""'); | ||
} | ||
return `"${val}"`; | ||
} | ||
}; | ||
@@ -395,3 +565,3 @@ | ||
if (newArrayKeys.length !== arrayKeys.length) throw new Error('Parameters arrayKeys and newArrayKeys should have same length'); | ||
if (!Array.isArray(obj)) throw new Error ('Object is not array'); | ||
if (!Array.isArray(obj)) throw new Error('Object is not array'); | ||
if (!obj[0]) throw new Error('Object error'); | ||
@@ -403,3 +573,3 @@ const out = new Array(obj.length); | ||
const elem = obj[index]; | ||
if (!Array.isArray(elem[arrayKeys[0]])) throw new Error ('Object array property is not array'); | ||
if (!Array.isArray(elem[arrayKeys[0]])) throw new Error('Object array property is not array'); | ||
let newKeyObj = new Array(elem[arrayKeys[0]].length); | ||
@@ -414,3 +584,3 @@ for (let i = 0; i < newKeyObj.length; i++) newKeyObj[i] = {}; | ||
{ | ||
if (!Array.isArray(arr)) throw new Error ('Object array property is not array'); | ||
if (!Array.isArray(arr)) throw new Error('Object array property is not array'); | ||
if (arr.length !== newKeyObj.length) throw new Error('Arrays have different lengths'); | ||
@@ -433,3 +603,3 @@ } | ||
if (newArrayKeys.length !== arrayKeys.length) throw new Error('Parameters arrayKeys and newArrayKeys should have same length'); | ||
if (!Array.isArray(obj)) throw new Error ('Object is not array'); | ||
if (!Array.isArray(obj)) throw new Error('Object is not array'); | ||
if (!obj[0]) throw new Error('Object error'); | ||
@@ -442,3 +612,3 @@ const out = new Array(obj.length); | ||
const objArray = elem[objArrayKey]; | ||
if (!Array.isArray(objArray)) throw new Error ('Object array property is not array'); | ||
if (!Array.isArray(objArray)) throw new Error('Object array property is not array'); | ||
for (let keyIndex = 0; keyIndex < arrayKeys.length; keyIndex++) | ||
@@ -445,0 +615,0 @@ { |
{ | ||
"name": "csv-to-js-parser", | ||
"version": "2.2.3", | ||
"version": "2.3.0", | ||
"description": "Converting csv data into array of JavaScript objects. This module can group input data.", | ||
@@ -5,0 +5,0 @@ "main": "app.js", |
@@ -0,1 +1,13 @@ | ||
## Версия 2.3. Что нового? | ||
В новой версии была добавлена корректная обработка двойных кавычек (") согласно [rfc4180](https://datatracker.ietf.org/doc/html/rfc4180). | ||
* Теперь значения в полях могут обрамляться кавычками, например | ||
"aaa","bbb" | ||
* Внутри кавычек можно использовать символы разделителя или даже переноса строки: | ||
"aaa,aa","bbb | ||
bb" | ||
* Также поле может содержать сам символ ("), но его нужно предварительно экранировать: | ||
"aaa""aa","bbb""aaa""bb" | ||
* Поля не обрамлённые в двойные кавычки, но содержащие этот символ тоже корректно обработаются: | ||
aa"aa,bb"aaa"bbb | ||
# Преобразование данных csv в объекты JavaScript | ||
@@ -2,0 +14,0 @@ |
@@ -0,1 +1,13 @@ | ||
## Version 2.3. What's new? | ||
The new version added correct handling of double quotes (") according to [rfc4180](https://datatracker.ietf.org/doc/html/rfc4180). | ||
* Values in fields can now be surrounded by quotes, for example | ||
"aaa","bbb" | ||
* Now you can use separator character or even line breaks inside quotes: | ||
"aaa,aa","bbb | ||
bb" | ||
* Also, the field can contain the symbol (") itself, but it must be escaped: | ||
"aaa""aa","bbb""aaa""bb" | ||
* Fields that are not surrounded by double quotes, but containing this characters will also be processed correctly: | ||
aa"aa,bb"aaa"bbb | ||
# Convert csv data to an array of JavaScript objects | ||
@@ -2,0 +14,0 @@ |
@@ -33,3 +33,2 @@ 'use strict'; | ||
const not_normal_csv_sorted = | ||
@@ -98,5 +97,5 @@ `customer_id;customer_name;product;price;closed;customer_status;product_id | ||
` | ||
`; | ||
const not_unique_csv_sorted_1_2 = | ||
const not_unique_csv_sorted_1_2 = | ||
`sex;age;person_id | ||
@@ -125,3 +124,3 @@ female;30;9 | ||
const not_unique_csv_sorted_3 = | ||
const not_unique_csv_sorted_3 = | ||
`person_id;sex;age | ||
@@ -150,3 +149,3 @@ 1;male;30 | ||
const not_unique_not_normal_csv_sorted_1_2 = | ||
const not_unique_not_normal_csv_sorted_1_2 = | ||
`sex;age;person_id | ||
@@ -175,3 +174,3 @@ female;;9 | ||
const not_unique_obj_var1 = | ||
const not_unique_obj_var1 = | ||
[ | ||
@@ -280,3 +279,3 @@ { | ||
const not_unique_not_normal_obj_var1 = | ||
const not_unique_not_normal_obj_var1 = | ||
[ | ||
@@ -385,5 +384,3 @@ { | ||
const not_unique_obj_var2 = | ||
const not_unique_obj_var2 = | ||
[ | ||
@@ -422,3 +419,3 @@ { | ||
const not_unique_not_normal_obj_var2 = | ||
const not_unique_not_normal_obj_var2 = | ||
[ | ||
@@ -477,4 +474,3 @@ { | ||
const not_unique_obj_var3 = | ||
const not_unique_obj_var3 = | ||
[ | ||
@@ -553,3 +549,3 @@ { | ||
const normal_obj = | ||
const normal_obj = | ||
[ | ||
@@ -585,3 +581,3 @@ { | ||
const not_normal_obj = | ||
const not_normal_obj = | ||
[ | ||
@@ -617,3 +613,3 @@ { | ||
const normal_obj_with_combine_arrays = | ||
const normal_obj_with_combine_arrays = | ||
[ | ||
@@ -703,30 +699,30 @@ { | ||
{ | ||
customer_id: {type: 'number', group: 1}, | ||
product: {type: 'string'}, | ||
product_id: {type: 'number'}, | ||
customer_name: {type: 'string', group: 2}, | ||
price: {type: 'number'}, | ||
closed: {type: 'boolean'}, | ||
customer_status: {type: 'number', group: 2} | ||
customer_id: { type: 'number', group: 1 }, | ||
product: { type: 'string' }, | ||
product_id: { type: 'number' }, | ||
customer_name: { type: 'string', group: 2 }, | ||
price: { type: 'number' }, | ||
closed: { type: 'boolean' }, | ||
customer_status: { type: 'number', group: 2 } | ||
}; | ||
const not_unique_description_var1 = | ||
const not_unique_description_var1 = | ||
{ | ||
age: {type: 'number', group: 1}, | ||
sex: {type: 'string', group: 2}, | ||
person_id: {type: 'number', group: 3} | ||
age: { type: 'number', group: 1 }, | ||
sex: { type: 'string', group: 2 }, | ||
person_id: { type: 'number', group: 3 } | ||
}; | ||
const not_unique_description_var2 = | ||
const not_unique_description_var2 = | ||
{ | ||
age: {type: 'number', group: 1}, | ||
sex: {type: 'string', group: 2}, | ||
person_id: {type: 'number'} | ||
age: { type: 'number', group: 1 }, | ||
sex: { type: 'string', group: 2 }, | ||
person_id: { type: 'number' } | ||
}; | ||
const not_unique_description_var3 = | ||
const not_unique_description_var3 = | ||
{ | ||
age: {type: 'number'}, | ||
sex: {type: 'string', group: 2}, | ||
person_id: {type: 'number', group: 1} | ||
age: { type: 'number' }, | ||
sex: { type: 'string', group: 2 }, | ||
person_id: { type: 'number', group: 1 } | ||
}; | ||
@@ -749,8 +745,8 @@ | ||
} | ||
it ('should return normal object', () => doTest(normal_csv, normal_obj, normal_description)); | ||
it ('should return not_normal object', () => doTest(not_normal_csv, not_normal_obj, normal_description)); | ||
it ('should return not_unique_obj_var1 object', () => doTest(not_unique_csv, not_unique_obj_var1, not_unique_description_var1)); | ||
it ('should return not_unique_obj_var2 object', () => doTest(not_unique_csv, not_unique_obj_var2, not_unique_description_var2)); | ||
it ('should return not_unique_obj_var3 object', () => doTest(not_unique_csv, not_unique_obj_var3, not_unique_description_var3)); | ||
it ('should return not_unique_obj_var1 object (no description)', () => | ||
it('should return normal object', () => doTest(normal_csv, normal_obj, normal_description)); | ||
it('should return not_normal object', () => doTest(not_normal_csv, not_normal_obj, normal_description)); | ||
it('should return not_unique_obj_var1 object', () => doTest(not_unique_csv, not_unique_obj_var1, not_unique_description_var1)); | ||
it('should return not_unique_obj_var2 object', () => doTest(not_unique_csv, not_unique_obj_var2, not_unique_description_var2)); | ||
it('should return not_unique_obj_var3 object', () => doTest(not_unique_csv, not_unique_obj_var3, not_unique_description_var3)); | ||
it('should return not_unique_obj_var1 object (no description)', () => | ||
{ | ||
@@ -778,7 +774,5 @@ //Convert all properties of not_unique_description_var1 to String | ||
const result = app.objToCsv(obj, ';'); | ||
const result1 = app.objToCsv(obj, ';'); | ||
const result2 = app.objToCsv(obj); | ||
//fs.writeFileSync('expected.csv', expected); | ||
//fs.writeFileSync('result.csv', result); | ||
if (result1 !== expected) throw new Error(`Expected (explicit delimeter):\n${expected}\n\nBut got:\n${result}`); | ||
@@ -800,13 +794,58 @@ let commaExpected = expected.replace(/;/g, ','); | ||
it('should return normal_obj_with_combine_arrays', () => | ||
{ | ||
const result = app.combineArrays(normal_obj, 'products', ['product_id', 'product', 'price', 'closed'], ['product_id', 'name', 'price', 'closed']); | ||
let msg = whereNotEqual(normal_obj_with_combine_arrays, result); | ||
if (msg) throw new Error(msg); | ||
}); | ||
{ | ||
const result = app.combineArrays(normal_obj, 'products', ['product_id', 'product', 'price', 'closed'], ['product_id', 'name', 'price', 'closed']); | ||
let msg = whereNotEqual(normal_obj_with_combine_arrays, result); | ||
if (msg) throw new Error(msg); | ||
}); | ||
it('should return normal_obj', () => | ||
{ | ||
const result = app.separateArrays(normal_obj_with_combine_arrays, 'products', ['product_id', 'name', 'price', 'closed'], ['product_id', 'product', 'price', 'closed']); | ||
let msg = whereNotEqual(normal_obj, result); | ||
if (msg) throw new Error(msg); | ||
}); | ||
}); | ||
describe('Double quotes specification test (rfc4180)', () => | ||
{ | ||
const csv_for_csvToObj = '"aaa","bb""b",ccc\r\na"aa,"bbb,",",x,"",y\r\nz","yyy"\r\nxx x,yyy"a"y,\r\n"xxx" ,"yyy""a"", y","zzz,a,z"\r\nxxx, "yyy""v,v\r\nay","a, """\r\nzzz,"zz""aaa"z,"zzz"\r\n'; | ||
const csv_for_objToCsv = 'aaa,"bb""b",ccc\r\n"a""aa","bbb,",",x,"",y\r\nz"\r\nxx x,"yyy""a""y",\r\nxxx,"yyy""a"", y","zzz,a,z"\r\nxxx,"yyy""v,v\r\nay","a, """\r\nzzz,"""zz""""aaa""z",zzz\r\n'; | ||
const obj = | ||
[ | ||
{ | ||
const result = app.separateArrays(normal_obj_with_combine_arrays, 'products', ['product_id', 'name', 'price', 'closed'], ['product_id', 'product', 'price', 'closed']); | ||
let msg = whereNotEqual(normal_obj, result); | ||
if (msg) throw new Error(msg); | ||
}); | ||
aaa: 'a"aa', | ||
'bb"b': 'bbb,', | ||
ccc: ',x,",y\r\nz' | ||
}, | ||
{ | ||
aaa: 'xx x', | ||
'bb"b': 'yyy"a"y', | ||
ccc: null | ||
}, | ||
{ | ||
aaa: 'xxx', | ||
'bb"b': 'yyy"a", y', | ||
ccc: 'zzz,a,z' | ||
}, | ||
{ | ||
aaa: 'xxx', | ||
'bb"b': 'yyy"v,v\r\nay', | ||
ccc: 'a, "' | ||
}, | ||
{ | ||
aaa: 'zzz', | ||
'bb"b': '"zz""aaa"z', | ||
ccc: 'zzz' | ||
}, | ||
]; | ||
it('csvToObj should handle double quotes correctly according to rfc 4180', () => | ||
{ | ||
const result = app.csvToObj(csv_for_csvToObj); | ||
const msg = whereNotEqual(obj, result); | ||
if (msg) throw new Error(msg); | ||
}); | ||
it('objToCsv should handle double quotes correctly according to rfc 4180', () => | ||
{ | ||
const result = app.objToCsv(obj, ',', 'crlf'); | ||
if (result !== csv_for_objToCsv) throw new Error('Returned csv is incorrect.'); | ||
}); | ||
}); | ||
@@ -828,3 +867,3 @@ | ||
{ | ||
if (typeof(expectedArr[j]) === 'object') | ||
if (typeof (expectedArr[j]) === 'object') | ||
{ | ||
@@ -843,3 +882,3 @@ for (let key in expectedArr[j]) | ||
{ | ||
if (expectedArr[j]!== resultArr[j]) | ||
if (expectedArr[j] !== resultArr[j]) | ||
{ | ||
@@ -846,0 +885,0 @@ flag = true; |
65791
10
1517
336