@thi.ng/csv 2.4.7 → 2.5.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2025-08-04T09:13:01Z
3
+ - **Last updated**: 2025-08-06T11:48:03Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -11,6 +11,24 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
11
11
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
12
12
  and/or version bumps of transitive dependencies.
13
13
 
14
+ ### [2.5.1](https://github.com/thi-ng/umbrella/tree/@thi.ng/csv@2.5.1) (2025-08-06)
15
+
16
+ #### ♻️ Refactoring
17
+
18
+ - update default value handling (fn lookup) ([8d373bb](https://github.com/thi-ng/umbrella/commit/8d373bb))
19
+ - allow `ColumnSpec.default` to be functions
20
+ - update `parseCSV()`
21
+ - update tests
22
+
23
+ ## [2.5.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/csv@2.5.0) (2025-08-06)
24
+
25
+ #### 🚀 Features
26
+
27
+ - add support for column default values ([e105548](https://github.com/thi-ng/umbrella/commit/e105548))
28
+ - update `ColumnSpec`
29
+ - update `parseCSV()` to support & validate column specs w/ default values
30
+ - add tests
31
+
14
32
  ## [2.4.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/csv@2.4.0) (2025-07-12)
15
33
 
16
34
  #### 🚀 Features
package/README.md CHANGED
@@ -87,12 +87,13 @@ For Node.js REPL:
87
87
  const csv = await import("@thi.ng/csv");
88
88
  ```
89
89
 
90
- Package sizes (brotli'd, pre-treeshake): ESM: 1.56 KB
90
+ Package sizes (brotli'd, pre-treeshake): ESM: 1.71 KB
91
91
 
92
92
  ## Dependencies
93
93
 
94
94
  - [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
95
95
  - [@thi.ng/checks](https://github.com/thi-ng/umbrella/tree/develop/packages/checks)
96
+ - [@thi.ng/errors](https://github.com/thi-ng/umbrella/tree/develop/packages/errors)
96
97
  - [@thi.ng/strings](https://github.com/thi-ng/umbrella/tree/develop/packages/strings)
97
98
  - [@thi.ng/transducers](https://github.com/thi-ng/umbrella/tree/develop/packages/transducers)
98
99
 
package/api.d.ts CHANGED
@@ -16,7 +16,9 @@ export type CSVRecord = Record<string, any>;
16
16
  export type CellTransform = Fn2<string, any, any>;
17
17
  export interface ColumnSpec {
18
18
  /**
19
- * Rename column to given name in result objects.
19
+ * Rename column to given name in result objects. MUST be given if
20
+ * {@link ColumnSpec.default} is defined and column specs are provided to
21
+ * {@link parseCSV} as array (rather than as object).
20
22
  */
21
23
  alias?: string;
22
24
  /**
@@ -25,6 +27,15 @@ export interface ColumnSpec {
25
27
  * actual value for the cell.
26
28
  */
27
29
  tx?: CellTransform;
30
+ /**
31
+ * Default value or function to use if column is missing. If `default` is a
32
+ * function, it will be called with the entire {@link CSVRecord} constructed
33
+ * so far and the return value used as default.
34
+ *
35
+ * @remarks
36
+ * Also see note about {@link ColumnSpec.alias}.
37
+ */
38
+ default?: any;
28
39
  }
29
40
  export type ColumnSpecs = Record<string, ColumnSpec>;
30
41
  export interface CommonCSVOpts {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/csv",
3
- "version": "2.4.7",
3
+ "version": "2.5.1",
4
4
  "description": "Customizable, transducer-based CSV parser/object mapper and transformer",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -41,6 +41,7 @@
41
41
  "dependencies": {
42
42
  "@thi.ng/api": "^8.12.1",
43
43
  "@thi.ng/checks": "^3.7.15",
44
+ "@thi.ng/errors": "^2.5.41",
44
45
  "@thi.ng/strings": "^3.9.21",
45
46
  "@thi.ng/transducers": "^9.6.6"
46
47
  },
@@ -87,5 +88,5 @@
87
88
  "thi.ng": {
88
89
  "year": 2014
89
90
  },
90
- "gitHead": "0bcedf8d1dd4f30cd06bb2c668599628f2f0141e\n"
91
+ "gitHead": "a07af3b3e8e8f3b07e326156bd1fce36b9a97108\n"
91
92
  }
package/parse.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { isArray } from "@thi.ng/checks/is-array";
2
2
  import { isFunction } from "@thi.ng/checks/is-function";
3
3
  import { isIterable } from "@thi.ng/checks/is-iterable";
4
+ import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
4
5
  import { ESCAPES } from "@thi.ng/strings/escape";
5
6
  import { split } from "@thi.ng/strings/split";
6
7
  import { compR } from "@thi.ng/transducers/compr";
@@ -28,12 +29,16 @@ function parseCSV(opts, src) {
28
29
  const reduce = rfn[2];
29
30
  let index;
30
31
  let revIndex;
32
+ let defaults;
31
33
  let first = true;
32
34
  let isQuoted = false;
33
35
  let record = [];
34
36
  const init = (header2) => {
35
- cols && (index = __initIndex(header2, cols));
36
- all && (revIndex = __initRevIndex(header2));
37
+ if (cols) {
38
+ index = __initIndex(header2, cols);
39
+ defaults = __initDefaults(cols);
40
+ }
41
+ if (all) revIndex = __initRevIndex(header2);
37
42
  first = false;
38
43
  };
39
44
  const collectAll = (row) => record.reduce(
@@ -49,6 +54,12 @@ function parseCSV(opts, src) {
49
54
  }
50
55
  return acc;
51
56
  }, row);
57
+ const collectDefaults = (row) => defaults.reduce((acc, { alias, default: val }) => {
58
+ if (acc[alias] === void 0) {
59
+ acc[alias] = isFunction(val) ? val(acc) : val;
60
+ }
61
+ return acc;
62
+ }, row);
52
63
  header && init(header);
53
64
  return compR(rfn, (acc, line) => {
54
65
  if ((!line.length || line.startsWith(comment)) && !isQuoted)
@@ -65,6 +76,7 @@ function parseCSV(opts, src) {
65
76
  const row = {};
66
77
  all && collectAll(row);
67
78
  index && collectIndexed(row);
79
+ defaults && collectDefaults(row);
68
80
  record = [];
69
81
  return reduce(acc, row);
70
82
  } else {
@@ -185,6 +197,25 @@ const __initIndex = (line, cols) => isArray(cols) ? cols.reduce((acc, spec, i) =
185
197
  {}
186
198
  );
187
199
  const __initRevIndex = (line) => line.reduce((acc, x, i) => (acc[i] = x, acc), {});
200
+ const __initDefaults = (cols) => {
201
+ const defaults = isArray(cols) ? cols.filter((c) => {
202
+ if (!c || c.default == void 0) return false;
203
+ if (!c.alias)
204
+ illegalArgs(
205
+ `missing column alias for default: ${c.default}`
206
+ );
207
+ return true;
208
+ }) : Object.entries(cols).reduce((acc, [k, v]) => {
209
+ if (v.default !== void 0) {
210
+ acc.push({
211
+ alias: v.alias ?? k,
212
+ default: v.default
213
+ });
214
+ }
215
+ return acc;
216
+ }, []);
217
+ return defaults.length ? defaults : void 0;
218
+ };
188
219
  export {
189
220
  parseCSV,
190
221
  parseCSVFromString,