forked from willfarrell/csv-rex
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathformat.js
101 lines (84 loc) · 2.53 KB
/
format.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
96
97
98
99
100
101
export const defaultOptions = {
header: true, // false: don't log out header; true: log out header
// columns: undefined, // [] to set order of headers and allowed columns
newlineChar: '\r\n', // undefined: detect newline from file; '\r\n': Windows; '\n': Linux/Mac
delimiterChar: ',', // TODO add in auto detect or function
quoteChar: '"'
// escapeChar: '"'
// quoteColumn: undefined
}
export const format = (input, opts = {}) => {
const options = { ...defaultOptions, enqueue: () => {}, ...opts }
options.escapeChar ??= options.quoteChar
const { enableReturn, enqueue } = options
const isArrayData = Array.isArray(input[0])
const format = isArrayData ? formatArray : formatObject
const includeHeader = options.header !== false
options.columns ??= Object.keys(input[0])
let res = includeHeader ? formatArray(options.columns, options) : ''
for (let i = 0, l = input.length; i < l; i++) {
const data = format(input[i], options)
enqueue(data)
if (enableReturn) {
res += data
}
}
return enableReturn && res
}
export const formatArray = (arr, options) => {
let csv = ''
for (let i = 0, l = arr.length; i < l; i++) {
csv += (i ? options.delimiterChar : '') + formatField(arr[i], null, options)
}
return csv + options.newlineChar
}
export const formatObject = (data, options) => {
let csv = ''
for (let i = 0, l = options.columns.length; i < l; i++) {
csv +=
(i ? options.delimiterChar : '') +
formatField(data[options.columns[i]], options.quoteColumn?.[i], options)
}
return csv + options.newlineChar
}
export const formatField = (
field,
needsQuotes,
{ quoteChar, escapeChar, delimiterChar, newlineChar }
) => {
if (field === undefined || field === null || field === '') {
return ''
}
if (field.constructor === Date) {
return field.toISOString() // JSON.stringify(str).slice(1, 25) faster??
}
field = field.toString()
// Developer override using options.quotes
if (needsQuotes === false) {
return field
}
// Test if needs quote
needsQuotes =
needsQuotes ||
hasAnyDelimiters(field, [
delimiterChar,
newlineChar,
quoteChar,
'\ufeff'
]) ||
field[0] === ' ' ||
field[field.length - 1] === ' '
return needsQuotes
? quoteChar +
field.replaceAll(quoteChar, escapeChar + quoteChar) +
quoteChar
: field
}
const hasAnyDelimiters = (field, delimiters) => {
for (const delimiter of delimiters) {
if (field.indexOf(delimiter) > -1) {
return true
}
}
}
export default format