-
Notifications
You must be signed in to change notification settings - Fork 41
/
csv-parser.js
95 lines (83 loc) · 2.04 KB
/
csv-parser.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"use strict";
const CHAR_DOUBLE_QUOTE = 34;
const CHAR_CR = 13;
const CHAR_LF = 10;
const CHAR_COMMA = 44;
// https://tools.ietf.org/html/rfc4180#section-2
function parseCsv(data) {
const rows = [];
let row = [];
let field = "";
let escapedState = false;
let i = 0;
function addField() {
row.push(field);
field = "";
}
function addRow() {
rows.push(row);
row = [];
// Ignore empty lines
while ([CHAR_LF, CHAR_CR].includes(data.charCodeAt(i + 1))) i++;
}
data = data.trim() + "\n";
for (i; i < data.length; i++) {
const char = data.charAt(i);
switch (data.charCodeAt(i)) {
case CHAR_DOUBLE_QUOTE:
if (!escapedState) {
// quoted field started
if (field.length) throw new Error("Invalid CSV format");
escapedState = true;
} else {
const nextChar = data.charCodeAt(i + 1);
if (nextChar === CHAR_DOUBLE_QUOTE) {
field += char;
i++;
} else if (nextChar && ![CHAR_COMMA, CHAR_CR, CHAR_LF].includes(nextChar)) {
throw new Error("Invalid CSV format");
} else {
// quoted field ended
escapedState = false;
}
}
break;
case CHAR_COMMA:
if (!escapedState) addField();
else field += char;
break;
case CHAR_CR:
case CHAR_LF:
if (!escapedState) {
addField();
addRow();
}
else {
field += char;
}
break;
default:
field += char;
break;
}
}
if (escapedState) throw new Error("Invalid CSV format");
return rows;
}
function reduce(rows, headerFirstRow = true) {
if (headerFirstRow) {
const headers = rows.shift();
return rows.map(row => {
let obj = {};
for (let i = 0; i < headers.length; i++)
obj[headers[i]] = row[i];
return obj;
});
} else {
return rows.map(row => {
return Object.assign({}, row);
});
}
}
exports.parseCsv = parseCsv;
exports.reduce = reduce;