@naturalcycles/nodejs-lib 12.89.0 → 12.90.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.
@@ -7,7 +7,7 @@ export interface CSVWriterConfig {
7
7
  /**
8
8
  * Array of columns
9
9
  */
10
- columns: string[];
10
+ columns?: string[];
11
11
  /**
12
12
  * Default: true
13
13
  */
@@ -15,7 +15,9 @@ export interface CSVWriterConfig {
15
15
  }
16
16
  export declare class CSVWriter {
17
17
  constructor(cfg: CSVWriterConfig);
18
- cfg: Required<CSVWriterConfig>;
18
+ cfg: CSVWriterConfig & {
19
+ delimiter: string;
20
+ };
19
21
  writeRows(rows: AnyObject[]): string;
20
22
  writeHeader(): string;
21
23
  writeRow(row: AnyObject): string;
@@ -23,4 +25,8 @@ export declare class CSVWriter {
23
25
  private quote;
24
26
  private shouldQuote;
25
27
  }
26
- export declare function arrayToCSVString(arr: AnyObject[], cfg: CSVWriterConfig): string;
28
+ export declare function arrayToCSVString(arr: AnyObject[], cfg?: CSVWriterConfig): string;
29
+ /**
30
+ * Iterates over the whole array and notes all possible columns.
31
+ */
32
+ export declare function arrayToCSVColumns(arr: AnyObject[]): string[];
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  // Inspired by: https://github.com/ryu1kn/csv-writer/
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.arrayToCSVString = exports.CSVWriter = void 0;
4
+ exports.arrayToCSVColumns = exports.arrayToCSVString = exports.CSVWriter = void 0;
5
+ const js_lib_1 = require("@naturalcycles/js-lib");
5
6
  class CSVWriter {
6
7
  constructor(cfg) {
7
8
  this.cfg = {
@@ -12,15 +13,19 @@ class CSVWriter {
12
13
  }
13
14
  writeRows(rows) {
14
15
  let s = '';
15
- if (this.cfg.includeHeader) {
16
+ // Detect columns based on content, if not defined upfront
17
+ this.cfg.columns ||= arrayToCSVColumns(rows);
18
+ if (this.cfg.includeHeader && rows.length) {
16
19
  s += this.writeHeader() + '\n';
17
20
  }
18
21
  return s + rows.map(row => this.writeRow(row)).join('\n');
19
22
  }
20
23
  writeHeader() {
24
+ (0, js_lib_1._assert)(this.cfg.columns, 'CSVWriter cannot writeHeader, because columns were not provided');
21
25
  return this.cfg.columns.map(col => this.quoteIfNeeded(col)).join(this.cfg.delimiter);
22
26
  }
23
27
  writeRow(row) {
28
+ (0, js_lib_1._assert)(this.cfg.columns, 'CSVWriter cannot writeRow, because columns were not provided');
24
29
  return this.cfg.columns
25
30
  .map(col => this.quoteIfNeeded(String(row[col] ?? '')))
26
31
  .join(this.cfg.delimiter);
@@ -32,12 +37,21 @@ class CSVWriter {
32
37
  return `"${s.replace(/"/g, '""')}"`;
33
38
  }
34
39
  shouldQuote(s) {
35
- return s.includes(this.cfg.delimiter) || s.includes('\r') || s.includes('\n') || s.includes('"');
40
+ return s.includes(this.cfg.delimiter) || s.includes('"') || s.includes('\n') || s.includes('\r');
36
41
  }
37
42
  }
38
43
  exports.CSVWriter = CSVWriter;
39
- function arrayToCSVString(arr, cfg) {
44
+ function arrayToCSVString(arr, cfg = {}) {
40
45
  const writer = new CSVWriter(cfg);
41
46
  return writer.writeRows(arr);
42
47
  }
43
48
  exports.arrayToCSVString = arrayToCSVString;
49
+ /**
50
+ * Iterates over the whole array and notes all possible columns.
51
+ */
52
+ function arrayToCSVColumns(arr) {
53
+ const cols = new Set();
54
+ arr.forEach(row => Object.keys(row).forEach(col => cols.add(col)));
55
+ return [...cols];
56
+ }
57
+ exports.arrayToCSVColumns = arrayToCSVColumns;
@@ -12,4 +12,9 @@ export interface TransformToCSVOptions extends CSVWriterConfig {
12
12
  /**
13
13
  * Transforms objects (objectMode=true) into chunks \n-terminated CSV strings (readableObjectMode=false).
14
14
  */
15
- export declare function transformToCSV<IN extends AnyObject = any>(opt: TransformToCSVOptions): TransformTyped<IN, string>;
15
+ export declare function transformToCSV<IN extends AnyObject = any>(opt: TransformToCSVOptions & {
16
+ /**
17
+ * Columns are required, as they cannot be detected on the fly.
18
+ */
19
+ columns: string[];
20
+ }): TransformTyped<IN, string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
- "version": "12.89.0",
3
+ "version": "12.90.1",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "docs-serve": "vuepress dev docs",
@@ -1,6 +1,6 @@
1
1
  // Inspired by: https://github.com/ryu1kn/csv-writer/
2
2
 
3
- import { AnyObject } from '@naturalcycles/js-lib'
3
+ import { _assert, AnyObject } from '@naturalcycles/js-lib'
4
4
 
5
5
  export interface CSVWriterConfig {
6
6
  /**
@@ -11,7 +11,7 @@ export interface CSVWriterConfig {
11
11
  /**
12
12
  * Array of columns
13
13
  */
14
- columns: string[]
14
+ columns?: string[]
15
15
 
16
16
  /**
17
17
  * Default: true
@@ -28,21 +28,27 @@ export class CSVWriter {
28
28
  }
29
29
  }
30
30
 
31
- public cfg: Required<CSVWriterConfig>
31
+ public cfg: CSVWriterConfig & { delimiter: string }
32
32
 
33
33
  writeRows(rows: AnyObject[]): string {
34
34
  let s = ''
35
- if (this.cfg.includeHeader) {
35
+
36
+ // Detect columns based on content, if not defined upfront
37
+ this.cfg.columns ||= arrayToCSVColumns(rows)
38
+
39
+ if (this.cfg.includeHeader && rows.length) {
36
40
  s += this.writeHeader() + '\n'
37
41
  }
38
42
  return s + rows.map(row => this.writeRow(row)).join('\n')
39
43
  }
40
44
 
41
45
  writeHeader(): string {
46
+ _assert(this.cfg.columns, 'CSVWriter cannot writeHeader, because columns were not provided')
42
47
  return this.cfg.columns.map(col => this.quoteIfNeeded(col)).join(this.cfg.delimiter)
43
48
  }
44
49
 
45
50
  writeRow(row: AnyObject): string {
51
+ _assert(this.cfg.columns, 'CSVWriter cannot writeRow, because columns were not provided')
46
52
  return this.cfg.columns
47
53
  .map(col => this.quoteIfNeeded(String(row[col] ?? '')))
48
54
  .join(this.cfg.delimiter)
@@ -57,11 +63,20 @@ export class CSVWriter {
57
63
  }
58
64
 
59
65
  private shouldQuote(s: string): boolean {
60
- return s.includes(this.cfg.delimiter) || s.includes('\r') || s.includes('\n') || s.includes('"')
66
+ return s.includes(this.cfg.delimiter) || s.includes('"') || s.includes('\n') || s.includes('\r')
61
67
  }
62
68
  }
63
69
 
64
- export function arrayToCSVString(arr: AnyObject[], cfg: CSVWriterConfig): string {
70
+ export function arrayToCSVString(arr: AnyObject[], cfg: CSVWriterConfig = {}): string {
65
71
  const writer = new CSVWriter(cfg)
66
72
  return writer.writeRows(arr)
67
73
  }
74
+
75
+ /**
76
+ * Iterates over the whole array and notes all possible columns.
77
+ */
78
+ export function arrayToCSVColumns(arr: AnyObject[]): string[] {
79
+ const cols = new Set<string>()
80
+ arr.forEach(row => Object.keys(row).forEach(col => cols.add(col)))
81
+ return [...cols]
82
+ }
@@ -16,7 +16,12 @@ export interface TransformToCSVOptions extends CSVWriterConfig {
16
16
  * Transforms objects (objectMode=true) into chunks \n-terminated CSV strings (readableObjectMode=false).
17
17
  */
18
18
  export function transformToCSV<IN extends AnyObject = any>(
19
- opt: TransformToCSVOptions,
19
+ opt: TransformToCSVOptions & {
20
+ /**
21
+ * Columns are required, as they cannot be detected on the fly.
22
+ */
23
+ columns: string[]
24
+ },
20
25
  ): TransformTyped<IN, string> {
21
26
  const { strict = true } = opt
22
27
  const writer = new CSVWriter(opt)