@thi.ng/csv 2.3.46 → 2.3.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -1
- package/api.js +0 -1
- package/format.js +51 -58
- package/package.json +10 -8
- package/parse.js +169 -194
- package/transforms.js +36 -80
package/CHANGELOG.md
CHANGED
package/api.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/format.js
CHANGED
|
@@ -6,62 +6,55 @@ import { iterator } from "@thi.ng/transducers/iterator";
|
|
|
6
6
|
import { isReduced } from "@thi.ng/transducers/reduced";
|
|
7
7
|
import { str } from "@thi.ng/transducers/str";
|
|
8
8
|
import { transduce } from "@thi.ng/transducers/transduce";
|
|
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
|
-
header = $row;
|
|
56
|
-
}
|
|
57
|
-
headerDone = true;
|
|
58
|
-
!isReduced(acc) && (acc = reduce(acc, line));
|
|
59
|
-
return acc;
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
return reduce(acc, line);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
};
|
|
9
|
+
function formatCSV(opts, src) {
|
|
10
|
+
return isIterable(src) ? iterator(formatCSV(opts), src) : (rfn) => {
|
|
11
|
+
let { header, cols, delim, quote } = {
|
|
12
|
+
delim: ",",
|
|
13
|
+
quote: `"`,
|
|
14
|
+
cols: [],
|
|
15
|
+
...opts
|
|
16
|
+
};
|
|
17
|
+
let colTx;
|
|
18
|
+
const reQuote = new RegExp(quote, "g");
|
|
19
|
+
const reduce = rfn[2];
|
|
20
|
+
let headerDone = false;
|
|
21
|
+
return compR(rfn, (acc, row) => {
|
|
22
|
+
if (!headerDone) {
|
|
23
|
+
if (!header && !isArray(row)) {
|
|
24
|
+
header = Object.keys(row);
|
|
25
|
+
}
|
|
26
|
+
colTx = isArray(cols) ? cols : header ? header.map(
|
|
27
|
+
(id) => cols[id]
|
|
28
|
+
) : [];
|
|
29
|
+
}
|
|
30
|
+
const $row = isArray(row) ? row : header.map((k) => row[k]);
|
|
31
|
+
const line = (header || $row).map((_, i) => {
|
|
32
|
+
const val = $row[i];
|
|
33
|
+
const cell = val != null ? colTx[i] ? colTx[i](val) : String(val) : "";
|
|
34
|
+
return cell.indexOf(quote) !== -1 ? wrap(quote)(
|
|
35
|
+
cell.replace(
|
|
36
|
+
reQuote,
|
|
37
|
+
`${quote}${quote}`
|
|
38
|
+
)
|
|
39
|
+
) : cell;
|
|
40
|
+
}).join(delim);
|
|
41
|
+
if (!headerDone) {
|
|
42
|
+
if (header) {
|
|
43
|
+
acc = reduce(acc, header.join(delim));
|
|
44
|
+
} else {
|
|
45
|
+
header = $row;
|
|
46
|
+
}
|
|
47
|
+
headerDone = true;
|
|
48
|
+
!isReduced(acc) && (acc = reduce(acc, line));
|
|
49
|
+
return acc;
|
|
50
|
+
} else {
|
|
51
|
+
return reduce(acc, line);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
};
|
|
66
55
|
}
|
|
67
|
-
|
|
56
|
+
const formatCSVString = (opts = {}, src) => transduce(formatCSV(opts), str(opts.rowDelim || "\n"), src);
|
|
57
|
+
export {
|
|
58
|
+
formatCSV,
|
|
59
|
+
formatCSVString
|
|
60
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/csv",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.48",
|
|
4
4
|
"description": "Customizable, transducer-based CSV parser/object mapper and transformer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"author": "Karsten Schmidt (https://thi.ng)",
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "yarn
|
|
27
|
+
"build": "yarn build:esbuild && yarn build:decl",
|
|
28
|
+
"build:decl": "tsc --declaration --emitDeclarationOnly",
|
|
29
|
+
"build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
|
|
28
30
|
"clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",
|
|
29
31
|
"doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
|
|
30
32
|
"doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
|
|
@@ -33,14 +35,14 @@
|
|
|
33
35
|
"test": "bun test"
|
|
34
36
|
},
|
|
35
37
|
"dependencies": {
|
|
36
|
-
"@thi.ng/api": "^8.9.
|
|
37
|
-
"@thi.ng/checks": "^3.4.
|
|
38
|
-
"@thi.ng/strings": "^3.7.
|
|
39
|
-
"@thi.ng/transducers": "^8.8.
|
|
38
|
+
"@thi.ng/api": "^8.9.12",
|
|
39
|
+
"@thi.ng/checks": "^3.4.12",
|
|
40
|
+
"@thi.ng/strings": "^3.7.3",
|
|
41
|
+
"@thi.ng/transducers": "^8.8.15"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
42
44
|
"@microsoft/api-extractor": "^7.38.3",
|
|
43
|
-
"
|
|
45
|
+
"esbuild": "^0.19.8",
|
|
44
46
|
"rimraf": "^5.0.5",
|
|
45
47
|
"tools": "^0.0.1",
|
|
46
48
|
"typedoc": "^0.25.4",
|
|
@@ -84,5 +86,5 @@
|
|
|
84
86
|
"thi.ng": {
|
|
85
87
|
"year": 2014
|
|
86
88
|
},
|
|
87
|
-
"gitHead": "
|
|
89
|
+
"gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n"
|
|
88
90
|
}
|
package/parse.js
CHANGED
|
@@ -5,204 +5,179 @@ import { ESCAPES } from "@thi.ng/strings/escape";
|
|
|
5
5
|
import { split } from "@thi.ng/strings/split";
|
|
6
6
|
import { compR } from "@thi.ng/transducers/compr";
|
|
7
7
|
import { iterator1 } from "@thi.ng/transducers/iterator";
|
|
8
|
-
/**
|
|
9
|
-
* Default parser options.
|
|
10
|
-
*
|
|
11
|
-
* @internal
|
|
12
|
-
*/
|
|
13
8
|
const DEFAULT_OPTS = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
delim: ",",
|
|
10
|
+
quote: '"',
|
|
11
|
+
comment: "#",
|
|
12
|
+
trim: false
|
|
18
13
|
};
|
|
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
|
-
|
|
14
|
+
function parseCSV(opts, src) {
|
|
15
|
+
return isIterable(src) ? iterator1(parseCSV(opts), src) : (rfn) => {
|
|
16
|
+
const { all, cols, delim, quote, comment, trim, header } = {
|
|
17
|
+
all: true,
|
|
18
|
+
...DEFAULT_OPTS,
|
|
19
|
+
...opts
|
|
20
|
+
};
|
|
21
|
+
const reduce = rfn[2];
|
|
22
|
+
let index;
|
|
23
|
+
let revIndex;
|
|
24
|
+
let first = true;
|
|
25
|
+
let isQuoted = false;
|
|
26
|
+
let record = [];
|
|
27
|
+
const init = (header2) => {
|
|
28
|
+
cols && (index = initIndex(header2, cols));
|
|
29
|
+
all && (revIndex = initRevIndex(header2));
|
|
30
|
+
first = false;
|
|
31
|
+
};
|
|
32
|
+
const collectAll = (row) => record.reduce(
|
|
33
|
+
(acc, x, i) => (acc[revIndex[i]] = trim ? x.trim() : x, acc),
|
|
34
|
+
row
|
|
35
|
+
);
|
|
36
|
+
const collectIndexed = (row) => Object.entries(index).reduce((acc, [id, { i, spec }]) => {
|
|
37
|
+
let val = record[i];
|
|
38
|
+
if (val !== void 0) {
|
|
39
|
+
trim && (val = val.trim());
|
|
40
|
+
all && spec.alias && delete acc[id];
|
|
41
|
+
acc[spec.alias || id] = spec.tx ? spec.tx(val, acc) : val;
|
|
42
|
+
}
|
|
43
|
+
return acc;
|
|
44
|
+
}, row);
|
|
45
|
+
header && init(header);
|
|
46
|
+
return compR(rfn, (acc, line) => {
|
|
47
|
+
if ((!line.length || line.startsWith(comment)) && !isQuoted)
|
|
48
|
+
return acc;
|
|
49
|
+
if (!first) {
|
|
50
|
+
isQuoted = parseLine(
|
|
51
|
+
line,
|
|
52
|
+
record,
|
|
53
|
+
isQuoted,
|
|
54
|
+
delim,
|
|
55
|
+
quote
|
|
56
|
+
);
|
|
57
|
+
if (isQuoted)
|
|
58
|
+
return acc;
|
|
59
|
+
const row = {};
|
|
60
|
+
all && collectAll(row);
|
|
61
|
+
index && collectIndexed(row);
|
|
62
|
+
record = [];
|
|
63
|
+
return reduce(acc, row);
|
|
64
|
+
} else {
|
|
65
|
+
isQuoted = parseLine(
|
|
66
|
+
line,
|
|
67
|
+
record,
|
|
68
|
+
isQuoted,
|
|
69
|
+
delim,
|
|
70
|
+
quote
|
|
71
|
+
);
|
|
72
|
+
if (!isQuoted) {
|
|
73
|
+
init(record);
|
|
74
|
+
record = [];
|
|
75
|
+
}
|
|
76
|
+
return acc;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
};
|
|
76
80
|
}
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
81
|
+
function parseCSVSimple(opts, src) {
|
|
82
|
+
return isIterable(src) ? iterator1(parseCSVSimple(opts), src) : (rfn) => {
|
|
83
|
+
const { cols, delim, quote, comment, trim, header } = {
|
|
84
|
+
header: true,
|
|
85
|
+
...DEFAULT_OPTS,
|
|
86
|
+
...opts
|
|
87
|
+
};
|
|
88
|
+
const reduce = rfn[2];
|
|
89
|
+
let first = header;
|
|
90
|
+
let isQuoted = false;
|
|
91
|
+
let record = [];
|
|
92
|
+
const collect = () => cols.reduce((acc, col, i) => {
|
|
93
|
+
if (col) {
|
|
94
|
+
let val = record[i];
|
|
95
|
+
if (val !== void 0) {
|
|
96
|
+
trim && (val = val.trim());
|
|
97
|
+
acc.push(isFunction(col) ? col(val, acc) : val);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return acc;
|
|
101
|
+
}, []);
|
|
102
|
+
return compR(rfn, (acc, line) => {
|
|
103
|
+
if ((!line.length || line.startsWith(comment)) && !isQuoted)
|
|
104
|
+
return acc;
|
|
105
|
+
if (!first) {
|
|
106
|
+
isQuoted = parseLine(
|
|
107
|
+
line,
|
|
108
|
+
record,
|
|
109
|
+
isQuoted,
|
|
110
|
+
delim,
|
|
111
|
+
quote
|
|
112
|
+
);
|
|
113
|
+
if (isQuoted)
|
|
114
|
+
return acc;
|
|
115
|
+
const row = cols ? collect() : record;
|
|
116
|
+
record = [];
|
|
117
|
+
return reduce(acc, row);
|
|
118
|
+
} else {
|
|
119
|
+
isQuoted = parseLine(
|
|
120
|
+
line,
|
|
121
|
+
record,
|
|
122
|
+
isQuoted,
|
|
123
|
+
delim,
|
|
124
|
+
quote
|
|
125
|
+
);
|
|
126
|
+
first = false;
|
|
127
|
+
record = [];
|
|
128
|
+
return acc;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
};
|
|
120
132
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
* given source string into a line based input using
|
|
124
|
-
* [`split()`](https://docs.thi.ng/umbrella/strings/functions/split.html).
|
|
125
|
-
*
|
|
126
|
-
* @param opts -
|
|
127
|
-
* @param src -
|
|
128
|
-
*/
|
|
129
|
-
export const parseCSVFromString = (opts, src) => parseCSV(opts, split(src));
|
|
130
|
-
/**
|
|
131
|
-
* Syntax sugar for iterator version of {@link parseCSVSimple}, efficiently
|
|
132
|
-
* splitting given source string into a line based input using
|
|
133
|
-
* [`split()`](https://docs.thi.ng/umbrella/strings/functions/split.html).
|
|
134
|
-
*
|
|
135
|
-
* @param opts -
|
|
136
|
-
* @param src -
|
|
137
|
-
*/
|
|
138
|
-
export const parseCSVSimpleFromString = (opts, src) => parseCSVSimple(opts, split(src));
|
|
139
|
-
/**
|
|
140
|
-
* Parses line into `acc`, taking quoted cell values and linebreaks into
|
|
141
|
-
* account.
|
|
142
|
-
*
|
|
143
|
-
* @remarks
|
|
144
|
-
* If `isQuoted` is true, the previous line ended with a quoted cell value,
|
|
145
|
-
* which might only end in the new or a future line. If that's the case, then
|
|
146
|
-
* the current line's contents will be added to the current last value of `acc`
|
|
147
|
-
* until the quoted cell is complete.
|
|
148
|
-
*
|
|
149
|
-
* Function returns current state of `isQuoted` (i.e. if line terminated in a
|
|
150
|
-
* quoted cell) and should be (re)called with new lines until it returns false.
|
|
151
|
-
*
|
|
152
|
-
* @param line -
|
|
153
|
-
* @param acc -
|
|
154
|
-
* @param isQuoted -
|
|
155
|
-
* @param delim -
|
|
156
|
-
* @param quote -
|
|
157
|
-
*/
|
|
133
|
+
const parseCSVFromString = (opts, src) => parseCSV(opts, split(src));
|
|
134
|
+
const parseCSVSimpleFromString = (opts, src) => parseCSVSimple(opts, split(src));
|
|
158
135
|
const parseLine = (line, acc, isQuoted, delim, quote) => {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
// field delimiter
|
|
184
|
-
else if (!isQuoted && c === delim) {
|
|
185
|
-
collectCell(acc, curr, openQuote);
|
|
186
|
-
openQuote = false;
|
|
187
|
-
curr = "";
|
|
188
|
-
}
|
|
189
|
-
// record unless escape seq start
|
|
190
|
-
else if (c !== "\\") {
|
|
191
|
-
curr += c;
|
|
192
|
-
}
|
|
193
|
-
p = c;
|
|
136
|
+
let curr = "";
|
|
137
|
+
let p = "";
|
|
138
|
+
let openQuote = isQuoted;
|
|
139
|
+
for (let i = 0, n = line.length; i < n; i++) {
|
|
140
|
+
const c = line[i];
|
|
141
|
+
if (p === "\\") {
|
|
142
|
+
curr += ESCAPES[c] || c;
|
|
143
|
+
} else if (c === quote) {
|
|
144
|
+
if (!isQuoted) {
|
|
145
|
+
p = "";
|
|
146
|
+
isQuoted = true;
|
|
147
|
+
continue;
|
|
148
|
+
} else if (p === quote) {
|
|
149
|
+
curr += quote;
|
|
150
|
+
p = "";
|
|
151
|
+
continue;
|
|
152
|
+
} else if (line[i + 1] !== quote)
|
|
153
|
+
isQuoted = false;
|
|
154
|
+
} else if (!isQuoted && c === delim) {
|
|
155
|
+
collectCell(acc, curr, openQuote);
|
|
156
|
+
openQuote = false;
|
|
157
|
+
curr = "";
|
|
158
|
+
} else if (c !== "\\") {
|
|
159
|
+
curr += c;
|
|
194
160
|
}
|
|
195
|
-
|
|
196
|
-
|
|
161
|
+
p = c;
|
|
162
|
+
}
|
|
163
|
+
curr !== "" && collectCell(acc, curr, openQuote);
|
|
164
|
+
return isQuoted;
|
|
165
|
+
};
|
|
166
|
+
const collectCell = (acc, curr, openQuote) => openQuote ? acc[acc.length - 1] += "\n" + curr : acc.push(curr);
|
|
167
|
+
const initIndex = (line, cols) => isArray(cols) ? cols.reduce((acc, spec, i) => {
|
|
168
|
+
if (spec) {
|
|
169
|
+
const alias = spec.alias || line[i] || String(i);
|
|
170
|
+
acc[alias] = { i, spec: { alias, ...spec } };
|
|
171
|
+
}
|
|
172
|
+
return acc;
|
|
173
|
+
}, {}) : line.reduce(
|
|
174
|
+
(acc, id, i) => cols[id] ? (acc[id] = { i, spec: cols[id] }, acc) : acc,
|
|
175
|
+
{}
|
|
176
|
+
);
|
|
177
|
+
const initRevIndex = (line) => line.reduce((acc, x, i) => (acc[i] = x, acc), {});
|
|
178
|
+
export {
|
|
179
|
+
parseCSV,
|
|
180
|
+
parseCSVFromString,
|
|
181
|
+
parseCSVSimple,
|
|
182
|
+
parseCSVSimpleFromString
|
|
197
183
|
};
|
|
198
|
-
const collectCell = (acc, curr, openQuote) => openQuote ? (acc[acc.length - 1] += "\n" + curr) : acc.push(curr);
|
|
199
|
-
const initIndex = (line, cols) => isArray(cols)
|
|
200
|
-
? cols.reduce((acc, spec, i) => {
|
|
201
|
-
if (spec) {
|
|
202
|
-
const alias = spec.alias || line[i] || String(i);
|
|
203
|
-
acc[alias] = { i, spec: { alias, ...spec } };
|
|
204
|
-
}
|
|
205
|
-
return acc;
|
|
206
|
-
}, {})
|
|
207
|
-
: line.reduce((acc, id, i) => cols[id] ? ((acc[id] = { i, spec: cols[id] }), acc) : acc, {});
|
|
208
|
-
const initRevIndex = (line) => line.reduce((acc, x, i) => ((acc[i] = x), acc), {});
|
package/transforms.js
CHANGED
|
@@ -1,85 +1,41 @@
|
|
|
1
1
|
import { padLeft } from "@thi.ng/strings/pad-left";
|
|
2
2
|
import { maybeParseFloat, maybeParseInt } from "@thi.ng/strings/parse";
|
|
3
3
|
import { percent as $percent } from "@thi.ng/strings/percent";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* @param x -
|
|
14
|
-
*/
|
|
15
|
-
export const lower = (x) => x.toLowerCase();
|
|
16
|
-
/**
|
|
17
|
-
* Higher-order cell parse value transform. Attempts to parse cell values as
|
|
18
|
-
* floating point number or returns `defaultVal` if not possible.
|
|
19
|
-
*
|
|
20
|
-
* @param defaultVal -
|
|
21
|
-
*/
|
|
22
|
-
export const float = (defaultVal = 0) => (x) => maybeParseFloat(x, defaultVal);
|
|
23
|
-
/**
|
|
24
|
-
* Higher-order cell parse value transform. Attempts to parse cell values as
|
|
25
|
-
* integer or returns `defaultVal` if not possible.
|
|
26
|
-
*
|
|
27
|
-
* @param defaultVal -
|
|
28
|
-
*/
|
|
29
|
-
export const int = (defaultVal = 0) => (x) => maybeParseInt(x, defaultVal, 10);
|
|
30
|
-
/**
|
|
31
|
-
* Higher-order cell parse value transform. Attempts to parse cell values as
|
|
32
|
-
* hexadecimal integer or returns `defaultVal` if not possible.
|
|
33
|
-
*
|
|
34
|
-
* @param defaultVal -
|
|
35
|
-
*/
|
|
36
|
-
export const hex = (defaultVal = 0) => (x) => maybeParseInt(x, defaultVal, 16);
|
|
37
|
-
export const percent = (x) => maybeParseFloat(x) * 0.01;
|
|
38
|
-
/**
|
|
39
|
-
* Higher-order cell parse value transform. Attempts to parse cell values as
|
|
40
|
-
* Unix epoch/timestamp or returns `defaultVal` if not possible.
|
|
41
|
-
*
|
|
42
|
-
* @param defaultVal -
|
|
43
|
-
*/
|
|
44
|
-
export const epoch = (defaultVal = 0) => (x) => {
|
|
45
|
-
const res = Date.parse(x);
|
|
46
|
-
return isNaN(res) ? defaultVal : res;
|
|
4
|
+
const upper = (x) => x.toUpperCase();
|
|
5
|
+
const lower = (x) => x.toLowerCase();
|
|
6
|
+
const float = (defaultVal = 0) => (x) => maybeParseFloat(x, defaultVal);
|
|
7
|
+
const int = (defaultVal = 0) => (x) => maybeParseInt(x, defaultVal, 10);
|
|
8
|
+
const hex = (defaultVal = 0) => (x) => maybeParseInt(x, defaultVal, 16);
|
|
9
|
+
const percent = (x) => maybeParseFloat(x) * 0.01;
|
|
10
|
+
const epoch = (defaultVal = 0) => (x) => {
|
|
11
|
+
const res = Date.parse(x);
|
|
12
|
+
return isNaN(res) ? defaultVal : res;
|
|
47
13
|
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
14
|
+
const date = (defaultVal) => (x) => {
|
|
15
|
+
const epoch2 = Date.parse(x);
|
|
16
|
+
if (isNaN(epoch2))
|
|
17
|
+
return defaultVal;
|
|
18
|
+
const res = /* @__PURE__ */ new Date();
|
|
19
|
+
res.setTime(epoch2);
|
|
20
|
+
return res;
|
|
21
|
+
};
|
|
22
|
+
const url = (x) => new URL(x);
|
|
23
|
+
const oneOf = (mappings, defaultVal) => (x) => mappings[x] ?? defaultVal;
|
|
24
|
+
const zeroPad = (digits) => padLeft(digits, "0");
|
|
25
|
+
const formatFloat = (prec = 2) => (x) => x.toFixed(prec);
|
|
26
|
+
const formatPercent = $percent;
|
|
27
|
+
export {
|
|
28
|
+
date,
|
|
29
|
+
epoch,
|
|
30
|
+
float,
|
|
31
|
+
formatFloat,
|
|
32
|
+
formatPercent,
|
|
33
|
+
hex,
|
|
34
|
+
int,
|
|
35
|
+
lower,
|
|
36
|
+
oneOf,
|
|
37
|
+
percent,
|
|
38
|
+
upper,
|
|
39
|
+
url,
|
|
40
|
+
zeroPad
|
|
61
41
|
};
|
|
62
|
-
/**
|
|
63
|
-
* Cell parse value transform. Attempts to parse cell values as JS `URL`
|
|
64
|
-
* instances.
|
|
65
|
-
*
|
|
66
|
-
* @param x -
|
|
67
|
-
*/
|
|
68
|
-
export const url = (x) => new URL(x);
|
|
69
|
-
/**
|
|
70
|
-
* Cell parse value transform. Accepts an object of mappings with original cell
|
|
71
|
-
* values as keys which are then mapped to arbitrary new values in an enum like
|
|
72
|
-
* fashion.
|
|
73
|
-
*
|
|
74
|
-
* @param mappings
|
|
75
|
-
* @param defaultVal
|
|
76
|
-
*/
|
|
77
|
-
export const oneOf = (mappings, defaultVal) => (x) => mappings[x] ?? defaultVal;
|
|
78
|
-
// formatters
|
|
79
|
-
export const zeroPad = (digits) => padLeft(digits, "0");
|
|
80
|
-
export const formatFloat = (prec = 2) => (x) => x.toFixed(prec);
|
|
81
|
-
/**
|
|
82
|
-
* Higher order cell value formatter. Takes normalized values and formats them
|
|
83
|
-
* as percentage with given `precision` (number of fractional digits).
|
|
84
|
-
*/
|
|
85
|
-
export const formatPercent = $percent;
|