|
10333
|
10392
|
"use strict"; |
|
10334
|
10393
|
module.exports = require("util"); |
|
10335
|
10394
|
|
|
|
10395
|
+/***/ }), |
|
|
10396
|
+ |
|
|
10397
|
+/***/ 4393: |
|
|
10398
|
+/***/ ((__unused_webpack_module, exports) => { |
|
|
10399
|
+ |
|
|
10400
|
+"use strict"; |
|
|
10401
|
+ |
|
|
10402
|
+ |
|
|
10403
|
+class CsvError extends Error { |
|
|
10404
|
+ constructor(code, message, options, ...contexts) { |
|
|
10405
|
+ if (Array.isArray(message)) message = message.join(" ").trim(); |
|
|
10406
|
+ super(message); |
|
|
10407
|
+ if (Error.captureStackTrace !== undefined) { |
|
|
10408
|
+ Error.captureStackTrace(this, CsvError); |
|
|
10409
|
+ } |
|
|
10410
|
+ this.code = code; |
|
|
10411
|
+ for (const context of contexts) { |
|
|
10412
|
+ for (const key in context) { |
|
|
10413
|
+ const value = context[key]; |
|
|
10414
|
+ this[key] = Buffer.isBuffer(value) |
|
|
10415
|
+ ? value.toString(options.encoding) |
|
|
10416
|
+ : value == null |
|
|
10417
|
+ ? value |
|
|
10418
|
+ : JSON.parse(JSON.stringify(value)); |
|
|
10419
|
+ } |
|
|
10420
|
+ } |
|
|
10421
|
+ } |
|
|
10422
|
+} |
|
|
10423
|
+ |
|
|
10424
|
+const is_object = function (obj) { |
|
|
10425
|
+ return typeof obj === "object" && obj !== null && !Array.isArray(obj); |
|
|
10426
|
+}; |
|
|
10427
|
+ |
|
|
10428
|
+const normalize_columns_array = function (columns) { |
|
|
10429
|
+ const normalizedColumns = []; |
|
|
10430
|
+ for (let i = 0, l = columns.length; i < l; i++) { |
|
|
10431
|
+ const column = columns[i]; |
|
|
10432
|
+ if (column === undefined || column === null || column === false) { |
|
|
10433
|
+ normalizedColumns[i] = { disabled: true }; |
|
|
10434
|
+ } else if (typeof column === "string") { |
|
|
10435
|
+ normalizedColumns[i] = { name: column }; |
|
|
10436
|
+ } else if (is_object(column)) { |
|
|
10437
|
+ if (typeof column.name !== "string") { |
|
|
10438
|
+ throw new CsvError("CSV_OPTION_COLUMNS_MISSING_NAME", [ |
|
|
10439
|
+ "Option columns missing name:", |
|
|
10440
|
+ `property "name" is required at position ${i}`, |
|
|
10441
|
+ "when column is an object literal", |
|
|
10442
|
+ ]); |
|
|
10443
|
+ } |
|
|
10444
|
+ normalizedColumns[i] = column; |
|
|
10445
|
+ } else { |
|
|
10446
|
+ throw new CsvError("CSV_INVALID_COLUMN_DEFINITION", [ |
|
|
10447
|
+ "Invalid column definition:", |
|
|
10448
|
+ "expect a string or a literal object,", |
|
|
10449
|
+ `got ${JSON.stringify(column)} at position ${i}`, |
|
|
10450
|
+ ]); |
|
|
10451
|
+ } |
|
|
10452
|
+ } |
|
|
10453
|
+ return normalizedColumns; |
|
|
10454
|
+}; |
|
|
10455
|
+ |
|
|
10456
|
+class ResizeableBuffer { |
|
|
10457
|
+ constructor(size = 100) { |
|
|
10458
|
+ this.size = size; |
|
|
10459
|
+ this.length = 0; |
|
|
10460
|
+ this.buf = Buffer.allocUnsafe(size); |
|
|
10461
|
+ } |
|
|
10462
|
+ prepend(val) { |
|
|
10463
|
+ if (Buffer.isBuffer(val)) { |
|
|
10464
|
+ const length = this.length + val.length; |
|
|
10465
|
+ if (length >= this.size) { |
|
|
10466
|
+ this.resize(); |
|
|
10467
|
+ if (length >= this.size) { |
|
|
10468
|
+ throw Error("INVALID_BUFFER_STATE"); |
|
|
10469
|
+ } |
|
|
10470
|
+ } |
|
|
10471
|
+ const buf = this.buf; |
|
|
10472
|
+ this.buf = Buffer.allocUnsafe(this.size); |
|
|
10473
|
+ val.copy(this.buf, 0); |
|
|
10474
|
+ buf.copy(this.buf, val.length); |
|
|
10475
|
+ this.length += val.length; |
|
|
10476
|
+ } else { |
|
|
10477
|
+ const length = this.length++; |
|
|
10478
|
+ if (length === this.size) { |
|
|
10479
|
+ this.resize(); |
|
|
10480
|
+ } |
|
|
10481
|
+ const buf = this.clone(); |
|
|
10482
|
+ this.buf[0] = val; |
|
|
10483
|
+ buf.copy(this.buf, 1, 0, length); |
|
|
10484
|
+ } |
|
|
10485
|
+ } |
|
|
10486
|
+ append(val) { |
|
|
10487
|
+ const length = this.length++; |
|
|
10488
|
+ if (length === this.size) { |
|
|
10489
|
+ this.resize(); |
|
|
10490
|
+ } |
|
|
10491
|
+ this.buf[length] = val; |
|
|
10492
|
+ } |
|
|
10493
|
+ clone() { |
|
|
10494
|
+ return Buffer.from(this.buf.slice(0, this.length)); |
|
|
10495
|
+ } |
|
|
10496
|
+ resize() { |
|
|
10497
|
+ const length = this.length; |
|
|
10498
|
+ this.size = this.size * 2; |
|
|
10499
|
+ const buf = Buffer.allocUnsafe(this.size); |
|
|
10500
|
+ this.buf.copy(buf, 0, 0, length); |
|
|
10501
|
+ this.buf = buf; |
|
|
10502
|
+ } |
|
|
10503
|
+ toString(encoding) { |
|
|
10504
|
+ if (encoding) { |
|
|
10505
|
+ return this.buf.slice(0, this.length).toString(encoding); |
|
|
10506
|
+ } else { |
|
|
10507
|
+ return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); |
|
|
10508
|
+ } |
|
|
10509
|
+ } |
|
|
10510
|
+ toJSON() { |
|
|
10511
|
+ return this.toString("utf8"); |
|
|
10512
|
+ } |
|
|
10513
|
+ reset() { |
|
|
10514
|
+ this.length = 0; |
|
|
10515
|
+ } |
|
|
10516
|
+} |
|
|
10517
|
+ |
|
|
10518
|
+// white space characters |
|
|
10519
|
+// https://en.wikipedia.org/wiki/Whitespace_character |
|
|
10520
|
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes#Types |
|
|
10521
|
+// \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff |
|
|
10522
|
+const np = 12; |
|
|
10523
|
+const cr$1 = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal |
|
|
10524
|
+const nl$1 = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal |
|
|
10525
|
+const space = 32; |
|
|
10526
|
+const tab = 9; |
|
|
10527
|
+ |
|
|
10528
|
+const init_state = function (options) { |
|
|
10529
|
+ return { |
|
|
10530
|
+ bomSkipped: false, |
|
|
10531
|
+ bufBytesStart: 0, |
|
|
10532
|
+ castField: options.cast_function, |
|
|
10533
|
+ commenting: false, |
|
|
10534
|
+ // Current error encountered by a record |
|
|
10535
|
+ error: undefined, |
|
|
10536
|
+ enabled: options.from_line === 1, |
|
|
10537
|
+ escaping: false, |
|
|
10538
|
+ escapeIsQuote: |
|
|
10539
|
+ Buffer.isBuffer(options.escape) && |
|
|
10540
|
+ Buffer.isBuffer(options.quote) && |
|
|
10541
|
+ Buffer.compare(options.escape, options.quote) === 0, |
|
|
10542
|
+ // columns can be `false`, `true`, `Array` |
|
|
10543
|
+ expectedRecordLength: Array.isArray(options.columns) |
|
|
10544
|
+ ? options.columns.length |
|
|
10545
|
+ : undefined, |
|
|
10546
|
+ field: new ResizeableBuffer(20), |
|
|
10547
|
+ firstLineToHeaders: options.cast_first_line_to_header, |
|
|
10548
|
+ needMoreDataSize: Math.max( |
|
|
10549
|
+ // Skip if the remaining buffer smaller than comment |
|
|
10550
|
+ options.comment !== null ? options.comment.length : 0, |
|
|
10551
|
+ // Skip if the remaining buffer can be delimiter |
|
|
10552
|
+ ...options.delimiter.map((delimiter) => delimiter.length), |
|
|
10553
|
+ // Skip if the remaining buffer can be escape sequence |
|
|
10554
|
+ options.quote !== null ? options.quote.length : 0, |
|
|
10555
|
+ ), |
|
|
10556
|
+ previousBuf: undefined, |
|
|
10557
|
+ quoting: false, |
|
|
10558
|
+ stop: false, |
|
|
10559
|
+ rawBuffer: new ResizeableBuffer(100), |
|
|
10560
|
+ record: [], |
|
|
10561
|
+ recordHasError: false, |
|
|
10562
|
+ record_length: 0, |
|
|
10563
|
+ recordDelimiterMaxLength: |
|
|
10564
|
+ options.record_delimiter.length === 0 |
|
|
10565
|
+ ? 0 |
|
|
10566
|
+ : Math.max(...options.record_delimiter.map((v) => v.length)), |
|
|
10567
|
+ trimChars: [ |
|
|
10568
|
+ Buffer.from(" ", options.encoding)[0], |
|
|
10569
|
+ Buffer.from("\t", options.encoding)[0], |
|
|
10570
|
+ ], |
|
|
10571
|
+ wasQuoting: false, |
|
|
10572
|
+ wasRowDelimiter: false, |
|
|
10573
|
+ timchars: [ |
|
|
10574
|
+ Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), |
|
|
10575
|
+ Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), |
|
|
10576
|
+ Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), |
|
|
10577
|
+ Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), |
|
|
10578
|
+ Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), |
|
|
10579
|
+ ], |
|
|
10580
|
+ }; |
|
|
10581
|
+}; |
|
|
10582
|
+ |
|
|
10583
|
+const underscore = function (str) { |
|
|
10584
|
+ return str.replace(/([A-Z])/g, function (_, match) { |
|
|
10585
|
+ return "_" + match.toLowerCase(); |
|
|
10586
|
+ }); |
|
|
10587
|
+}; |
|
|
10588
|
+ |
|
|
10589
|
+const normalize_options = function (opts) { |
|
|
10590
|
+ const options = {}; |
|
|
10591
|
+ // Merge with user options |
|
|
10592
|
+ for (const opt in opts) { |
|
|
10593
|
+ options[underscore(opt)] = opts[opt]; |
|
|
10594
|
+ } |
|
|
10595
|
+ // Normalize option `encoding` |
|
|
10596
|
+ // Note: defined first because other options depends on it |
|
|
10597
|
+ // to convert chars/strings into buffers. |
|
|
10598
|
+ if (options.encoding === undefined || options.encoding === true) { |
|
|
10599
|
+ options.encoding = "utf8"; |
|
|
10600
|
+ } else if (options.encoding === null || options.encoding === false) { |
|
|
10601
|
+ options.encoding = null; |
|
|
10602
|
+ } else if ( |
|
|
10603
|
+ typeof options.encoding !== "string" && |
|
|
10604
|
+ options.encoding !== null |
|
|
10605
|
+ ) { |
|
|
10606
|
+ throw new CsvError( |
|
|
10607
|
+ "CSV_INVALID_OPTION_ENCODING", |
|
|
10608
|
+ [ |
|
|
10609
|
+ "Invalid option encoding:", |
|
|
10610
|
+ "encoding must be a string or null to return a buffer,", |
|
|
10611
|
+ `got ${JSON.stringify(options.encoding)}`, |
|
|
10612
|
+ ], |
|
|
10613
|
+ options, |
|
|
10614
|
+ ); |
|
|
10615
|
+ } |
|
|
10616
|
+ // Normalize option `bom` |
|
|
10617
|
+ if ( |
|
|
10618
|
+ options.bom === undefined || |
|
|
10619
|
+ options.bom === null || |
|
|
10620
|
+ options.bom === false |
|
|
10621
|
+ ) { |
|
|
10622
|
+ options.bom = false; |
|
|
10623
|
+ } else if (options.bom !== true) { |
|
|
10624
|
+ throw new CsvError( |
|
|
10625
|
+ "CSV_INVALID_OPTION_BOM", |
|
|
10626
|
+ [ |
|
|
10627
|
+ "Invalid option bom:", |
|
|
10628
|
+ "bom must be true,", |
|
|
10629
|
+ `got ${JSON.stringify(options.bom)}`, |
|
|
10630
|
+ ], |
|
|
10631
|
+ options, |
|
|
10632
|
+ ); |
|
|
10633
|
+ } |
|
|
10634
|
+ // Normalize option `cast` |
|
|
10635
|
+ options.cast_function = null; |
|
|
10636
|
+ if ( |
|
|
10637
|
+ options.cast === undefined || |
|
|
10638
|
+ options.cast === null || |
|
|
10639
|
+ options.cast === false || |
|
|
10640
|
+ options.cast === "" |
|
|
10641
|
+ ) { |
|
|
10642
|
+ options.cast = undefined; |
|
|
10643
|
+ } else if (typeof options.cast === "function") { |
|
|
10644
|
+ options.cast_function = options.cast; |
|
|
10645
|
+ options.cast = true; |
|
|
10646
|
+ } else if (options.cast !== true) { |
|
|
10647
|
+ throw new CsvError( |
|
|
10648
|
+ "CSV_INVALID_OPTION_CAST", |
|
|
10649
|
+ [ |
|
|
10650
|
+ "Invalid option cast:", |
|
|
10651
|
+ "cast must be true or a function,", |
|
|
10652
|
+ `got ${JSON.stringify(options.cast)}`, |
|
|
10653
|
+ ], |
|
|
10654
|
+ options, |
|
|
10655
|
+ ); |
|
|
10656
|
+ } |
|
|
10657
|
+ // Normalize option `cast_date` |
|
|
10658
|
+ if ( |
|
|
10659
|
+ options.cast_date === undefined || |
|
|
10660
|
+ options.cast_date === null || |
|
|
10661
|
+ options.cast_date === false || |
|
|
10662
|
+ options.cast_date === "" |
|
|
10663
|
+ ) { |
|
|
10664
|
+ options.cast_date = false; |
|
|
10665
|
+ } else if (options.cast_date === true) { |
|
|
10666
|
+ options.cast_date = function (value) { |
|
|
10667
|
+ const date = Date.parse(value); |
|
|
10668
|
+ return !isNaN(date) ? new Date(date) : value; |
|
|
10669
|
+ }; |
|
|
10670
|
+ } else if (typeof options.cast_date !== "function") { |
|
|
10671
|
+ throw new CsvError( |
|
|
10672
|
+ "CSV_INVALID_OPTION_CAST_DATE", |
|
|
10673
|
+ [ |
|
|
10674
|
+ "Invalid option cast_date:", |
|
|
10675
|
+ "cast_date must be true or a function,", |
|
|
10676
|
+ `got ${JSON.stringify(options.cast_date)}`, |
|
|
10677
|
+ ], |
|
|
10678
|
+ options, |
|
|
10679
|
+ ); |
|
|
10680
|
+ } |
|
|
10681
|
+ // Normalize option `columns` |
|
|
10682
|
+ options.cast_first_line_to_header = null; |
|
|
10683
|
+ if (options.columns === true) { |
|
|
10684
|
+ // Fields in the first line are converted as-is to columns |
|
|
10685
|
+ options.cast_first_line_to_header = undefined; |
|
|
10686
|
+ } else if (typeof options.columns === "function") { |
|
|
10687
|
+ options.cast_first_line_to_header = options.columns; |
|
|
10688
|
+ options.columns = true; |
|
|
10689
|
+ } else if (Array.isArray(options.columns)) { |
|
|
10690
|
+ options.columns = normalize_columns_array(options.columns); |
|
|
10691
|
+ } else if ( |
|
|
10692
|
+ options.columns === undefined || |
|
|
10693
|
+ options.columns === null || |
|
|
10694
|
+ options.columns === false |
|
|
10695
|
+ ) { |
|
|
10696
|
+ options.columns = false; |
|
|
10697
|
+ } else { |
|
|
10698
|
+ throw new CsvError( |
|
|
10699
|
+ "CSV_INVALID_OPTION_COLUMNS", |
|
|
10700
|
+ [ |
|
|
10701
|
+ "Invalid option columns:", |
|
|
10702
|
+ "expect an array, a function or true,", |
|
|
10703
|
+ `got ${JSON.stringify(options.columns)}`, |
|
|
10704
|
+ ], |
|
|
10705
|
+ options, |
|
|
10706
|
+ ); |
|
|
10707
|
+ } |
|
|
10708
|
+ // Normalize option `group_columns_by_name` |
|
|
10709
|
+ if ( |
|
|
10710
|
+ options.group_columns_by_name === undefined || |
|
|
10711
|
+ options.group_columns_by_name === null || |
|
|
10712
|
+ options.group_columns_by_name === false |
|
|
10713
|
+ ) { |
|
|
10714
|
+ options.group_columns_by_name = false; |
|
|
10715
|
+ } else if (options.group_columns_by_name !== true) { |
|
|
10716
|
+ throw new CsvError( |
|
|
10717
|
+ "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", |
|
|
10718
|
+ [ |
|
|
10719
|
+ "Invalid option group_columns_by_name:", |
|
|
10720
|
+ "expect an boolean,", |
|
|
10721
|
+ `got ${JSON.stringify(options.group_columns_by_name)}`, |
|
|
10722
|
+ ], |
|
|
10723
|
+ options, |
|
|
10724
|
+ ); |
|
|
10725
|
+ } else if (options.columns === false) { |
|
|
10726
|
+ throw new CsvError( |
|
|
10727
|
+ "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", |
|
|
10728
|
+ [ |
|
|
10729
|
+ "Invalid option group_columns_by_name:", |
|
|
10730
|
+ "the `columns` mode must be activated.", |
|
|
10731
|
+ ], |
|
|
10732
|
+ options, |
|
|
10733
|
+ ); |
|
|
10734
|
+ } |
|
|
10735
|
+ // Normalize option `comment` |
|
|
10736
|
+ if ( |
|
|
10737
|
+ options.comment === undefined || |
|
|
10738
|
+ options.comment === null || |
|
|
10739
|
+ options.comment === false || |
|
|
10740
|
+ options.comment === "" |
|
|
10741
|
+ ) { |
|
|
10742
|
+ options.comment = null; |
|
|
10743
|
+ } else { |
|
|
10744
|
+ if (typeof options.comment === "string") { |
|
|
10745
|
+ options.comment = Buffer.from(options.comment, options.encoding); |
|
|
10746
|
+ } |
|
|
10747
|
+ if (!Buffer.isBuffer(options.comment)) { |
|
|
10748
|
+ throw new CsvError( |
|
|
10749
|
+ "CSV_INVALID_OPTION_COMMENT", |
|
|
10750
|
+ [ |
|
|
10751
|
+ "Invalid option comment:", |
|
|
10752
|
+ "comment must be a buffer or a string,", |
|
|
10753
|
+ `got ${JSON.stringify(options.comment)}`, |
|
|
10754
|
+ ], |
|
|
10755
|
+ options, |
|
|
10756
|
+ ); |
|
|
10757
|
+ } |
|
|
10758
|
+ } |
|
|
10759
|
+ // Normalize option `comment_no_infix` |
|
|
10760
|
+ if ( |
|
|
10761
|
+ options.comment_no_infix === undefined || |
|
|
10762
|
+ options.comment_no_infix === null || |
|
|
10763
|
+ options.comment_no_infix === false |
|
|
10764
|
+ ) { |
|
|
10765
|
+ options.comment_no_infix = false; |
|
|
10766
|
+ } else if (options.comment_no_infix !== true) { |
|
|
10767
|
+ throw new CsvError( |
|
|
10768
|
+ "CSV_INVALID_OPTION_COMMENT", |
|
|
10769
|
+ [ |
|
|
10770
|
+ "Invalid option comment_no_infix:", |
|
|
10771
|
+ "value must be a boolean,", |
|
|
10772
|
+ `got ${JSON.stringify(options.comment_no_infix)}`, |
|
|
10773
|
+ ], |
|
|
10774
|
+ options, |
|
|
10775
|
+ ); |
|
|
10776
|
+ } |
|
|
10777
|
+ // Normalize option `delimiter` |
|
|
10778
|
+ const delimiter_json = JSON.stringify(options.delimiter); |
|
|
10779
|
+ if (!Array.isArray(options.delimiter)) |
|
|
10780
|
+ options.delimiter = [options.delimiter]; |
|
|
10781
|
+ if (options.delimiter.length === 0) { |
|
|
10782
|
+ throw new CsvError( |
|
|
10783
|
+ "CSV_INVALID_OPTION_DELIMITER", |
|
|
10784
|
+ [ |
|
|
10785
|
+ "Invalid option delimiter:", |
|
|
10786
|
+ "delimiter must be a non empty string or buffer or array of string|buffer,", |
|
|
10787
|
+ `got ${delimiter_json}`, |
|
|
10788
|
+ ], |
|
|
10789
|
+ options, |
|
|
10790
|
+ ); |
|
|
10791
|
+ } |
|
|
10792
|
+ options.delimiter = options.delimiter.map(function (delimiter) { |
|
|
10793
|
+ if (delimiter === undefined || delimiter === null || delimiter === false) { |
|
|
10794
|
+ return Buffer.from(",", options.encoding); |
|
|
10795
|
+ } |
|
|
10796
|
+ if (typeof delimiter === "string") { |
|
|
10797
|
+ delimiter = Buffer.from(delimiter, options.encoding); |
|
|
10798
|
+ } |
|
|
10799
|
+ if (!Buffer.isBuffer(delimiter) || delimiter.length === 0) { |
|
|
10800
|
+ throw new CsvError( |
|
|
10801
|
+ "CSV_INVALID_OPTION_DELIMITER", |
|
|
10802
|
+ [ |
|
|
10803
|
+ "Invalid option delimiter:", |
|
|
10804
|
+ "delimiter must be a non empty string or buffer or array of string|buffer,", |
|
|
10805
|
+ `got ${delimiter_json}`, |
|
|
10806
|
+ ], |
|
|
10807
|
+ options, |
|
|
10808
|
+ ); |
|
|
10809
|
+ } |
|
|
10810
|
+ return delimiter; |
|
|
10811
|
+ }); |
|
|
10812
|
+ // Normalize option `escape` |
|
|
10813
|
+ if (options.escape === undefined || options.escape === true) { |
|
|
10814
|
+ options.escape = Buffer.from('"', options.encoding); |
|
|
10815
|
+ } else if (typeof options.escape === "string") { |
|
|
10816
|
+ options.escape = Buffer.from(options.escape, options.encoding); |
|
|
10817
|
+ } else if (options.escape === null || options.escape === false) { |
|
|
10818
|
+ options.escape = null; |
|
|
10819
|
+ } |
|
|
10820
|
+ if (options.escape !== null) { |
|
|
10821
|
+ if (!Buffer.isBuffer(options.escape)) { |
|
|
10822
|
+ throw new Error( |
|
|
10823
|
+ `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, |
|
|
10824
|
+ ); |
|
|
10825
|
+ } |
|
|
10826
|
+ } |
|
|
10827
|
+ // Normalize option `from` |
|
|
10828
|
+ if (options.from === undefined || options.from === null) { |
|
|
10829
|
+ options.from = 1; |
|
|
10830
|
+ } else { |
|
|
10831
|
+ if (typeof options.from === "string" && /\d+/.test(options.from)) { |
|
|
10832
|
+ options.from = parseInt(options.from); |
|
|
10833
|
+ } |
|
|
10834
|
+ if (Number.isInteger(options.from)) { |
|
|
10835
|
+ if (options.from < 0) { |
|
|
10836
|
+ throw new Error( |
|
|
10837
|
+ `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, |
|
|
10838
|
+ ); |
|
|
10839
|
+ } |
|
|
10840
|
+ } else { |
|
|
10841
|
+ throw new Error( |
|
|
10842
|
+ `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, |
|
|
10843
|
+ ); |
|
|
10844
|
+ } |
|
|
10845
|
+ } |
|
|
10846
|
+ // Normalize option `from_line` |
|
|
10847
|
+ if (options.from_line === undefined || options.from_line === null) { |
|
|
10848
|
+ options.from_line = 1; |
|
|
10849
|
+ } else { |
|
|
10850
|
+ if ( |
|
|
10851
|
+ typeof options.from_line === "string" && |
|
|
10852
|
+ /\d+/.test(options.from_line) |
|
|
10853
|
+ ) { |
|
|
10854
|
+ options.from_line = parseInt(options.from_line); |
|
|
10855
|
+ } |
|
|
10856
|
+ if (Number.isInteger(options.from_line)) { |
|
|
10857
|
+ if (options.from_line <= 0) { |
|
|
10858
|
+ throw new Error( |
|
|
10859
|
+ `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, |
|
|
10860
|
+ ); |
|
|
10861
|
+ } |
|
|
10862
|
+ } else { |
|
|
10863
|
+ throw new Error( |
|
|
10864
|
+ `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, |
|
|
10865
|
+ ); |
|
|
10866
|
+ } |
|
|
10867
|
+ } |
|
|
10868
|
+ // Normalize options `ignore_last_delimiters` |
|
|
10869
|
+ if ( |
|
|
10870
|
+ options.ignore_last_delimiters === undefined || |
|
|
10871
|
+ options.ignore_last_delimiters === null |
|
|
10872
|
+ ) { |
|
|
10873
|
+ options.ignore_last_delimiters = false; |
|
|
10874
|
+ } else if (typeof options.ignore_last_delimiters === "number") { |
|
|
10875
|
+ options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); |
|
|
10876
|
+ if (options.ignore_last_delimiters === 0) { |
|
|
10877
|
+ options.ignore_last_delimiters = false; |
|
|
10878
|
+ } |
|
|
10879
|
+ } else if (typeof options.ignore_last_delimiters !== "boolean") { |
|
|
10880
|
+ throw new CsvError( |
|
|
10881
|
+ "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", |
|
|
10882
|
+ [ |
|
|
10883
|
+ "Invalid option `ignore_last_delimiters`:", |
|
|
10884
|
+ "the value must be a boolean value or an integer,", |
|
|
10885
|
+ `got ${JSON.stringify(options.ignore_last_delimiters)}`, |
|
|
10886
|
+ ], |
|
|
10887
|
+ options, |
|
|
10888
|
+ ); |
|
|
10889
|
+ } |
|
|
10890
|
+ if (options.ignore_last_delimiters === true && options.columns === false) { |
|
|
10891
|
+ throw new CsvError( |
|
|
10892
|
+ "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", |
|
|
10893
|
+ [ |
|
|
10894
|
+ "The option `ignore_last_delimiters`", |
|
|
10895
|
+ "requires the activation of the `columns` option", |
|
|
10896
|
+ ], |
|
|
10897
|
+ options, |
|
|
10898
|
+ ); |
|
|
10899
|
+ } |
|
|
10900
|
+ // Normalize option `info` |
|
|
10901
|
+ if ( |
|
|
10902
|
+ options.info === undefined || |
|
|
10903
|
+ options.info === null || |
|
|
10904
|
+ options.info === false |
|
|
10905
|
+ ) { |
|
|
10906
|
+ options.info = false; |
|
|
10907
|
+ } else if (options.info !== true) { |
|
|
10908
|
+ throw new Error( |
|
|
10909
|
+ `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, |
|
|
10910
|
+ ); |
|
|
10911
|
+ } |
|
|
10912
|
+ // Normalize option `max_record_size` |
|
|
10913
|
+ if ( |
|
|
10914
|
+ options.max_record_size === undefined || |
|
|
10915
|
+ options.max_record_size === null || |
|
|
10916
|
+ options.max_record_size === false |
|
|
10917
|
+ ) { |
|
|
10918
|
+ options.max_record_size = 0; |
|
|
10919
|
+ } else if ( |
|
|
10920
|
+ Number.isInteger(options.max_record_size) && |
|
|
10921
|
+ options.max_record_size >= 0 |
|
|
10922
|
+ ) ; else if ( |
|
|
10923
|
+ typeof options.max_record_size === "string" && |
|
|
10924
|
+ /\d+/.test(options.max_record_size) |
|
|
10925
|
+ ) { |
|
|
10926
|
+ options.max_record_size = parseInt(options.max_record_size); |
|
|
10927
|
+ } else { |
|
|
10928
|
+ throw new Error( |
|
|
10929
|
+ `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, |
|
|
10930
|
+ ); |
|
|
10931
|
+ } |
|
|
10932
|
+ // Normalize option `objname` |
|
|
10933
|
+ if ( |
|
|
10934
|
+ options.objname === undefined || |
|
|
10935
|
+ options.objname === null || |
|
|
10936
|
+ options.objname === false |
|
|
10937
|
+ ) { |
|
|
10938
|
+ options.objname = undefined; |
|
|
10939
|
+ } else if (Buffer.isBuffer(options.objname)) { |
|
|
10940
|
+ if (options.objname.length === 0) { |
|
|
10941
|
+ throw new Error(`Invalid Option: objname must be a non empty buffer`); |
|
|
10942
|
+ } |
|
|
10943
|
+ if (options.encoding === null) ; else { |
|
|
10944
|
+ options.objname = options.objname.toString(options.encoding); |
|
|
10945
|
+ } |
|
|
10946
|
+ } else if (typeof options.objname === "string") { |
|
|
10947
|
+ if (options.objname.length === 0) { |
|
|
10948
|
+ throw new Error(`Invalid Option: objname must be a non empty string`); |
|
|
10949
|
+ } |
|
|
10950
|
+ // Great, nothing to do |
|
|
10951
|
+ } else if (typeof options.objname === "number") ; else { |
|
|
10952
|
+ throw new Error( |
|
|
10953
|
+ `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, |
|
|
10954
|
+ ); |
|
|
10955
|
+ } |
|
|
10956
|
+ if (options.objname !== undefined) { |
|
|
10957
|
+ if (typeof options.objname === "number") { |
|
|
10958
|
+ if (options.columns !== false) { |
|
|
10959
|
+ throw Error( |
|
|
10960
|
+ "Invalid Option: objname index cannot be combined with columns or be defined as a field", |
|
|
10961
|
+ ); |
|
|
10962
|
+ } |
|
|
10963
|
+ } else { |
|
|
10964
|
+ // A string or a buffer |
|
|
10965
|
+ if (options.columns === false) { |
|
|
10966
|
+ throw Error( |
|
|
10967
|
+ "Invalid Option: objname field must be combined with columns or be defined as an index", |
|
|
10968
|
+ ); |
|
|
10969
|
+ } |
|
|
10970
|
+ } |
|
|
10971
|
+ } |
|
|
10972
|
+ // Normalize option `on_record` |
|
|
10973
|
+ if (options.on_record === undefined || options.on_record === null) { |
|
|
10974
|
+ options.on_record = undefined; |
|
|
10975
|
+ } else if (typeof options.on_record !== "function") { |
|
|
10976
|
+ throw new CsvError( |
|
|
10977
|
+ "CSV_INVALID_OPTION_ON_RECORD", |
|
|
10978
|
+ [ |
|
|
10979
|
+ "Invalid option `on_record`:", |
|
|
10980
|
+ "expect a function,", |
|
|
10981
|
+ `got ${JSON.stringify(options.on_record)}`, |
|
|
10982
|
+ ], |
|
|
10983
|
+ options, |
|
|
10984
|
+ ); |
|
|
10985
|
+ } |
|
|
10986
|
+ // Normalize option `on_skip` |
|
|
10987
|
+ // options.on_skip ??= (err, chunk) => { |
|
|
10988
|
+ // this.emit('skip', err, chunk); |
|
|
10989
|
+ // }; |
|
|
10990
|
+ if ( |
|
|
10991
|
+ options.on_skip !== undefined && |
|
|
10992
|
+ options.on_skip !== null && |
|
|
10993
|
+ typeof options.on_skip !== "function" |
|
|
10994
|
+ ) { |
|
|
10995
|
+ throw new Error( |
|
|
10996
|
+ `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, |
|
|
10997
|
+ ); |
|
|
10998
|
+ } |
|
|
10999
|
+ // Normalize option `quote` |
|
|
11000
|
+ if ( |
|
|
11001
|
+ options.quote === null || |
|
|
11002
|
+ options.quote === false || |
|
|
11003
|
+ options.quote === "" |
|
|
11004
|
+ ) { |
|
|
11005
|
+ options.quote = null; |
|
|
11006
|
+ } else { |
|
|
11007
|
+ if (options.quote === undefined || options.quote === true) { |
|
|
11008
|
+ options.quote = Buffer.from('"', options.encoding); |
|
|
11009
|
+ } else if (typeof options.quote === "string") { |
|
|
11010
|
+ options.quote = Buffer.from(options.quote, options.encoding); |
|
|
11011
|
+ } |
|
|
11012
|
+ if (!Buffer.isBuffer(options.quote)) { |
|
|
11013
|
+ throw new Error( |
|
|
11014
|
+ `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, |
|
|
11015
|
+ ); |
|
|
11016
|
+ } |
|
|
11017
|
+ } |
|
|
11018
|
+ // Normalize option `raw` |
|
|
11019
|
+ if ( |
|
|
11020
|
+ options.raw === undefined || |
|
|
11021
|
+ options.raw === null || |
|
|
11022
|
+ options.raw === false |
|
|
11023
|
+ ) { |
|
|
11024
|
+ options.raw = false; |
|
|
11025
|
+ } else if (options.raw !== true) { |
|
|
11026
|
+ throw new Error( |
|
|
11027
|
+ `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, |
|
|
11028
|
+ ); |
|
|
11029
|
+ } |
|
|
11030
|
+ // Normalize option `record_delimiter` |
|
|
11031
|
+ if (options.record_delimiter === undefined) { |
|
|
11032
|
+ options.record_delimiter = []; |
|
|
11033
|
+ } else if ( |
|
|
11034
|
+ typeof options.record_delimiter === "string" || |
|
|
11035
|
+ Buffer.isBuffer(options.record_delimiter) |
|
|
11036
|
+ ) { |
|
|
11037
|
+ if (options.record_delimiter.length === 0) { |
|
|
11038
|
+ throw new CsvError( |
|
|
11039
|
+ "CSV_INVALID_OPTION_RECORD_DELIMITER", |
|
|
11040
|
+ [ |
|
|
11041
|
+ "Invalid option `record_delimiter`:", |
|
|
11042
|
+ "value must be a non empty string or buffer,", |
|
|
11043
|
+ `got ${JSON.stringify(options.record_delimiter)}`, |
|
|
11044
|
+ ], |
|
|
11045
|
+ options, |
|
|
11046
|
+ ); |
|
|
11047
|
+ } |
|
|
11048
|
+ options.record_delimiter = [options.record_delimiter]; |
|
|
11049
|
+ } else if (!Array.isArray(options.record_delimiter)) { |
|
|
11050
|
+ throw new CsvError( |
|
|
11051
|
+ "CSV_INVALID_OPTION_RECORD_DELIMITER", |
|
|
11052
|
+ [ |
|
|
11053
|
+ "Invalid option `record_delimiter`:", |
|
|
11054
|
+ "value must be a string, a buffer or array of string|buffer,", |
|
|
11055
|
+ `got ${JSON.stringify(options.record_delimiter)}`, |
|
|
11056
|
+ ], |
|
|
11057
|
+ options, |
|
|
11058
|
+ ); |
|
|
11059
|
+ } |
|
|
11060
|
+ options.record_delimiter = options.record_delimiter.map(function (rd, i) { |
|
|
11061
|
+ if (typeof rd !== "string" && !Buffer.isBuffer(rd)) { |
|
|
11062
|
+ throw new CsvError( |
|
|
11063
|
+ "CSV_INVALID_OPTION_RECORD_DELIMITER", |
|
|
11064
|
+ [ |
|
|
11065
|
+ "Invalid option `record_delimiter`:", |
|
|
11066
|
+ "value must be a string, a buffer or array of string|buffer", |
|
|
11067
|
+ `at index ${i},`, |
|
|
11068
|
+ `got ${JSON.stringify(rd)}`, |
|
|
11069
|
+ ], |
|
|
11070
|
+ options, |
|
|
11071
|
+ ); |
|
|
11072
|
+ } else if (rd.length === 0) { |
|
|
11073
|
+ throw new CsvError( |
|
|
11074
|
+ "CSV_INVALID_OPTION_RECORD_DELIMITER", |
|
|
11075
|
+ [ |
|
|
11076
|
+ "Invalid option `record_delimiter`:", |
|
|
11077
|
+ "value must be a non empty string or buffer", |
|
|
11078
|
+ `at index ${i},`, |
|
|
11079
|
+ `got ${JSON.stringify(rd)}`, |
|
|
11080
|
+ ], |
|
|
11081
|
+ options, |
|
|
11082
|
+ ); |
|
|
11083
|
+ } |
|
|
11084
|
+ if (typeof rd === "string") { |
|
|
11085
|
+ rd = Buffer.from(rd, options.encoding); |
|
|
11086
|
+ } |
|
|
11087
|
+ return rd; |
|
|
11088
|
+ }); |
|
|
11089
|
+ // Normalize option `relax_column_count` |
|
|
11090
|
+ if (typeof options.relax_column_count === "boolean") ; else if ( |
|
|
11091
|
+ options.relax_column_count === undefined || |
|
|
11092
|
+ options.relax_column_count === null |
|
|
11093
|
+ ) { |
|
|
11094
|
+ options.relax_column_count = false; |
|
|
11095
|
+ } else { |
|
|
11096
|
+ throw new Error( |
|
|
11097
|
+ `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, |
|
|
11098
|
+ ); |
|
|
11099
|
+ } |
|
|
11100
|
+ if (typeof options.relax_column_count_less === "boolean") ; else if ( |
|
|
11101
|
+ options.relax_column_count_less === undefined || |
|
|
11102
|
+ options.relax_column_count_less === null |
|
|
11103
|
+ ) { |
|
|
11104
|
+ options.relax_column_count_less = false; |
|
|
11105
|
+ } else { |
|
|
11106
|
+ throw new Error( |
|
|
11107
|
+ `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, |
|
|
11108
|
+ ); |
|
|
11109
|
+ } |
|
|
11110
|
+ if (typeof options.relax_column_count_more === "boolean") ; else if ( |
|
|
11111
|
+ options.relax_column_count_more === undefined || |
|
|
11112
|
+ options.relax_column_count_more === null |
|
|
11113
|
+ ) { |
|
|
11114
|
+ options.relax_column_count_more = false; |
|
|
11115
|
+ } else { |
|
|
11116
|
+ throw new Error( |
|
|
11117
|
+ `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, |
|
|
11118
|
+ ); |
|
|
11119
|
+ } |
|
|
11120
|
+ // Normalize option `relax_quotes` |
|
|
11121
|
+ if (typeof options.relax_quotes === "boolean") ; else if ( |
|
|
11122
|
+ options.relax_quotes === undefined || |
|
|
11123
|
+ options.relax_quotes === null |
|
|
11124
|
+ ) { |
|
|
11125
|
+ options.relax_quotes = false; |
|
|
11126
|
+ } else { |
|
|
11127
|
+ throw new Error( |
|
|
11128
|
+ `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, |
|
|
11129
|
+ ); |
|
|
11130
|
+ } |
|
|
11131
|
+ // Normalize option `skip_empty_lines` |
|
|
11132
|
+ if (typeof options.skip_empty_lines === "boolean") ; else if ( |
|
|
11133
|
+ options.skip_empty_lines === undefined || |
|
|
11134
|
+ options.skip_empty_lines === null |
|
|
11135
|
+ ) { |
|
|
11136
|
+ options.skip_empty_lines = false; |
|
|
11137
|
+ } else { |
|
|
11138
|
+ throw new Error( |
|
|
11139
|
+ `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, |
|
|
11140
|
+ ); |
|
|
11141
|
+ } |
|
|
11142
|
+ // Normalize option `skip_records_with_empty_values` |
|
|
11143
|
+ if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( |
|
|
11144
|
+ options.skip_records_with_empty_values === undefined || |
|
|
11145
|
+ options.skip_records_with_empty_values === null |
|
|
11146
|
+ ) { |
|
|
11147
|
+ options.skip_records_with_empty_values = false; |
|
|
11148
|
+ } else { |
|
|
11149
|
+ throw new Error( |
|
|
11150
|
+ `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, |
|
|
11151
|
+ ); |
|
|
11152
|
+ } |
|
|
11153
|
+ // Normalize option `skip_records_with_error` |
|
|
11154
|
+ if (typeof options.skip_records_with_error === "boolean") ; else if ( |
|
|
11155
|
+ options.skip_records_with_error === undefined || |
|
|
11156
|
+ options.skip_records_with_error === null |
|
|
11157
|
+ ) { |
|
|
11158
|
+ options.skip_records_with_error = false; |
|
|
11159
|
+ } else { |
|
|
11160
|
+ throw new Error( |
|
|
11161
|
+ `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, |
|
|
11162
|
+ ); |
|
|
11163
|
+ } |
|
|
11164
|
+ // Normalize option `rtrim` |
|
|
11165
|
+ if ( |
|
|
11166
|
+ options.rtrim === undefined || |
|
|
11167
|
+ options.rtrim === null || |
|
|
11168
|
+ options.rtrim === false |
|
|
11169
|
+ ) { |
|
|
11170
|
+ options.rtrim = false; |
|
|
11171
|
+ } else if (options.rtrim !== true) { |
|
|
11172
|
+ throw new Error( |
|
|
11173
|
+ `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, |
|
|
11174
|
+ ); |
|
|
11175
|
+ } |
|
|
11176
|
+ // Normalize option `ltrim` |
|
|
11177
|
+ if ( |
|
|
11178
|
+ options.ltrim === undefined || |
|
|
11179
|
+ options.ltrim === null || |
|
|
11180
|
+ options.ltrim === false |
|
|
11181
|
+ ) { |
|
|
11182
|
+ options.ltrim = false; |
|
|
11183
|
+ } else if (options.ltrim !== true) { |
|
|
11184
|
+ throw new Error( |
|
|
11185
|
+ `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, |
|
|
11186
|
+ ); |
|
|
11187
|
+ } |
|
|
11188
|
+ // Normalize option `trim` |
|
|
11189
|
+ if ( |
|
|
11190
|
+ options.trim === undefined || |
|
|
11191
|
+ options.trim === null || |
|
|
11192
|
+ options.trim === false |
|
|
11193
|
+ ) { |
|
|
11194
|
+ options.trim = false; |
|
|
11195
|
+ } else if (options.trim !== true) { |
|
|
11196
|
+ throw new Error( |
|
|
11197
|
+ `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, |
|
|
11198
|
+ ); |
|
|
11199
|
+ } |
|
|
11200
|
+ // Normalize options `trim`, `ltrim` and `rtrim` |
|
|
11201
|
+ if (options.trim === true && opts.ltrim !== false) { |
|
|
11202
|
+ options.ltrim = true; |
|
|
11203
|
+ } else if (options.ltrim !== true) { |
|
|
11204
|
+ options.ltrim = false; |
|
|
11205
|
+ } |
|
|
11206
|
+ if (options.trim === true && opts.rtrim !== false) { |
|
|
11207
|
+ options.rtrim = true; |
|
|
11208
|
+ } else if (options.rtrim !== true) { |
|
|
11209
|
+ options.rtrim = false; |
|
|
11210
|
+ } |
|
|
11211
|
+ // Normalize option `to` |
|
|
11212
|
+ if (options.to === undefined || options.to === null) { |
|
|
11213
|
+ options.to = -1; |
|
|
11214
|
+ } else { |
|
|
11215
|
+ if (typeof options.to === "string" && /\d+/.test(options.to)) { |
|
|
11216
|
+ options.to = parseInt(options.to); |
|
|
11217
|
+ } |
|
|
11218
|
+ if (Number.isInteger(options.to)) { |
|
|
11219
|
+ if (options.to <= 0) { |
|
|
11220
|
+ throw new Error( |
|
|
11221
|
+ `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, |
|
|
11222
|
+ ); |
|
|
11223
|
+ } |
|
|
11224
|
+ } else { |
|
|
11225
|
+ throw new Error( |
|
|
11226
|
+ `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, |
|
|
11227
|
+ ); |
|
|
11228
|
+ } |
|
|
11229
|
+ } |
|
|
11230
|
+ // Normalize option `to_line` |
|
|
11231
|
+ if (options.to_line === undefined || options.to_line === null) { |
|
|
11232
|
+ options.to_line = -1; |
|
|
11233
|
+ } else { |
|
|
11234
|
+ if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { |
|
|
11235
|
+ options.to_line = parseInt(options.to_line); |
|
|
11236
|
+ } |
|
|
11237
|
+ if (Number.isInteger(options.to_line)) { |
|
|
11238
|
+ if (options.to_line <= 0) { |
|
|
11239
|
+ throw new Error( |
|
|
11240
|
+ `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, |
|
|
11241
|
+ ); |
|
|
11242
|
+ } |
|
|
11243
|
+ } else { |
|
|
11244
|
+ throw new Error( |
|
|
11245
|
+ `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, |
|
|
11246
|
+ ); |
|
|
11247
|
+ } |
|
|
11248
|
+ } |
|
|
11249
|
+ return options; |
|
|
11250
|
+}; |
|
|
11251
|
+ |
|
|
11252
|
+const isRecordEmpty = function (record) { |
|
|
11253
|
+ return record.every( |
|
|
11254
|
+ (field) => |
|
|
11255
|
+ field == null || (field.toString && field.toString().trim() === ""), |
|
|
11256
|
+ ); |
|
|
11257
|
+}; |
|
|
11258
|
+ |
|
|
11259
|
+const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal |
|
|
11260
|
+const nl = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal |
|
|
11261
|
+ |
|
|
11262
|
+const boms = { |
|
|
11263
|
+ // Note, the following are equals: |
|
|
11264
|
+ // Buffer.from("\ufeff") |
|
|
11265
|
+ // Buffer.from([239, 187, 191]) |
|
|
11266
|
+ // Buffer.from('EFBBBF', 'hex') |
|
|
11267
|
+ utf8: Buffer.from([239, 187, 191]), |
|
|
11268
|
+ // Note, the following are equals: |
|
|
11269
|
+ // Buffer.from "\ufeff", 'utf16le |
|
|
11270
|
+ // Buffer.from([255, 254]) |
|
|
11271
|
+ utf16le: Buffer.from([255, 254]), |
|
|
11272
|
+}; |
|
|
11273
|
+ |
|
|
11274
|
+const transform = function (original_options = {}) { |
|
|
11275
|
+ const info = { |
|
|
11276
|
+ bytes: 0, |
|
|
11277
|
+ comment_lines: 0, |
|
|
11278
|
+ empty_lines: 0, |
|
|
11279
|
+ invalid_field_length: 0, |
|
|
11280
|
+ lines: 1, |
|
|
11281
|
+ records: 0, |
|
|
11282
|
+ }; |
|
|
11283
|
+ const options = normalize_options(original_options); |
|
|
11284
|
+ return { |
|
|
11285
|
+ info: info, |
|
|
11286
|
+ original_options: original_options, |
|
|
11287
|
+ options: options, |
|
|
11288
|
+ state: init_state(options), |
|
|
11289
|
+ __needMoreData: function (i, bufLen, end) { |
|
|
11290
|
+ if (end) return false; |
|
|
11291
|
+ const { encoding, escape, quote } = this.options; |
|
|
11292
|
+ const { quoting, needMoreDataSize, recordDelimiterMaxLength } = |
|
|
11293
|
+ this.state; |
|
|
11294
|
+ const numOfCharLeft = bufLen - i - 1; |
|
|
11295
|
+ const requiredLength = Math.max( |
|
|
11296
|
+ needMoreDataSize, |
|
|
11297
|
+ // Skip if the remaining buffer smaller than record delimiter |
|
|
11298
|
+ // If "record_delimiter" is yet to be discovered: |
|
|
11299
|
+ // 1. It is equals to `[]` and "recordDelimiterMaxLength" equals `0` |
|
|
11300
|
+ // 2. We set the length to windows line ending in the current encoding |
|
|
11301
|
+ // Note, that encoding is known from user or bom discovery at that point |
|
|
11302
|
+ // recordDelimiterMaxLength, |
|
|
11303
|
+ recordDelimiterMaxLength === 0 |
|
|
11304
|
+ ? Buffer.from("\r\n", encoding).length |
|
|
11305
|
+ : recordDelimiterMaxLength, |
|
|
11306
|
+ // Skip if remaining buffer can be an escaped quote |
|
|
11307
|
+ quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, |
|
|
11308
|
+ // Skip if remaining buffer can be record delimiter following the closing quote |
|
|
11309
|
+ quoting ? quote.length + recordDelimiterMaxLength : 0, |
|
|
11310
|
+ ); |
|
|
11311
|
+ return numOfCharLeft < requiredLength; |
|
|
11312
|
+ }, |
|
|
11313
|
+ // Central parser implementation |
|
|
11314
|
+ parse: function (nextBuf, end, push, close) { |
|
|
11315
|
+ const { |
|
|
11316
|
+ bom, |
|
|
11317
|
+ comment_no_infix, |
|
|
11318
|
+ encoding, |
|
|
11319
|
+ from_line, |
|
|
11320
|
+ ltrim, |
|
|
11321
|
+ max_record_size, |
|
|
11322
|
+ raw, |
|
|
11323
|
+ relax_quotes, |
|
|
11324
|
+ rtrim, |
|
|
11325
|
+ skip_empty_lines, |
|
|
11326
|
+ to, |
|
|
11327
|
+ to_line, |
|
|
11328
|
+ } = this.options; |
|
|
11329
|
+ let { comment, escape, quote, record_delimiter } = this.options; |
|
|
11330
|
+ const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; |
|
|
11331
|
+ let buf; |
|
|
11332
|
+ if (previousBuf === undefined) { |
|
|
11333
|
+ if (nextBuf === undefined) { |
|
|
11334
|
+ // Handle empty string |
|
|
11335
|
+ close(); |
|
|
11336
|
+ return; |
|
|
11337
|
+ } else { |
|
|
11338
|
+ buf = nextBuf; |
|
|
11339
|
+ } |
|
|
11340
|
+ } else if (previousBuf !== undefined && nextBuf === undefined) { |
|
|
11341
|
+ buf = previousBuf; |
|
|
11342
|
+ } else { |
|
|
11343
|
+ buf = Buffer.concat([previousBuf, nextBuf]); |
|
|
11344
|
+ } |
|
|
11345
|
+ // Handle UTF BOM |
|
|
11346
|
+ if (bomSkipped === false) { |
|
|
11347
|
+ if (bom === false) { |
|
|
11348
|
+ this.state.bomSkipped = true; |
|
|
11349
|
+ } else if (buf.length < 3) { |
|
|
11350
|
+ // No enough data |
|
|
11351
|
+ if (end === false) { |
|
|
11352
|
+ // Wait for more data |
|
|
11353
|
+ this.state.previousBuf = buf; |
|
|
11354
|
+ return; |
|
|
11355
|
+ } |
|
|
11356
|
+ } else { |
|
|
11357
|
+ for (const encoding in boms) { |
|
|
11358
|
+ if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { |
|
|
11359
|
+ // Skip BOM |
|
|
11360
|
+ const bomLength = boms[encoding].length; |
|
|
11361
|
+ this.state.bufBytesStart += bomLength; |
|
|
11362
|
+ buf = buf.slice(bomLength); |
|
|
11363
|
+ // Renormalize original options with the new encoding |
|
|
11364
|
+ this.options = normalize_options({ |
|
|
11365
|
+ ...this.original_options, |
|
|
11366
|
+ encoding: encoding, |
|
|
11367
|
+ }); |
|
|
11368
|
+ // Options will re-evaluate the Buffer with the new encoding |
|
|
11369
|
+ ({ comment, escape, quote } = this.options); |
|
|
11370
|
+ break; |
|
|
11371
|
+ } |
|
|
11372
|
+ } |
|
|
11373
|
+ this.state.bomSkipped = true; |
|
|
11374
|
+ } |
|
|
11375
|
+ } |
|
|
11376
|
+ const bufLen = buf.length; |
|
|
11377
|
+ let pos; |
|
|
11378
|
+ for (pos = 0; pos < bufLen; pos++) { |
|
|
11379
|
+ // Ensure we get enough space to look ahead |
|
|
11380
|
+ // There should be a way to move this out of the loop |
|
|
11381
|
+ if (this.__needMoreData(pos, bufLen, end)) { |
|
|
11382
|
+ break; |
|
|
11383
|
+ } |
|
|
11384
|
+ if (this.state.wasRowDelimiter === true) { |
|
|
11385
|
+ this.info.lines++; |
|
|
11386
|
+ this.state.wasRowDelimiter = false; |
|
|
11387
|
+ } |
|
|
11388
|
+ if (to_line !== -1 && this.info.lines > to_line) { |
|
|
11389
|
+ this.state.stop = true; |
|
|
11390
|
+ close(); |
|
|
11391
|
+ return; |
|
|
11392
|
+ } |
|
|
11393
|
+ // Auto discovery of record_delimiter, unix, mac and windows supported |
|
|
11394
|
+ if (this.state.quoting === false && record_delimiter.length === 0) { |
|
|
11395
|
+ const record_delimiterCount = this.__autoDiscoverRecordDelimiter( |
|
|
11396
|
+ buf, |
|
|
11397
|
+ pos, |
|
|
11398
|
+ ); |
|
|
11399
|
+ if (record_delimiterCount) { |
|
|
11400
|
+ record_delimiter = this.options.record_delimiter; |
|
|
11401
|
+ } |
|
|
11402
|
+ } |
|
|
11403
|
+ const chr = buf[pos]; |
|
|
11404
|
+ if (raw === true) { |
|
|
11405
|
+ rawBuffer.append(chr); |
|
|
11406
|
+ } |
|
|
11407
|
+ if ( |
|
|
11408
|
+ (chr === cr || chr === nl) && |
|
|
11409
|
+ this.state.wasRowDelimiter === false |
|
|
11410
|
+ ) { |
|
|
11411
|
+ this.state.wasRowDelimiter = true; |
|
|
11412
|
+ } |
|
|
11413
|
+ // Previous char was a valid escape char |
|
|
11414
|
+ // treat the current char as a regular char |
|
|
11415
|
+ if (this.state.escaping === true) { |
|
|
11416
|
+ this.state.escaping = false; |
|
|
11417
|
+ } else { |
|
|
11418
|
+ // Escape is only active inside quoted fields |
|
|
11419
|
+ // We are quoting, the char is an escape chr and there is a chr to escape |
|
|
11420
|
+ // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ |
|
|
11421
|
+ if ( |
|
|
11422
|
+ escape !== null && |
|
|
11423
|
+ this.state.quoting === true && |
|
|
11424
|
+ this.__isEscape(buf, pos, chr) && |
|
|
11425
|
+ pos + escape.length < bufLen |
|
|
11426
|
+ ) { |
|
|
11427
|
+ if (escapeIsQuote) { |
|
|
11428
|
+ if (this.__isQuote(buf, pos + escape.length)) { |
|
|
11429
|
+ this.state.escaping = true; |
|
|
11430
|
+ pos += escape.length - 1; |
|
|
11431
|
+ continue; |
|
|
11432
|
+ } |
|
|
11433
|
+ } else { |
|
|
11434
|
+ this.state.escaping = true; |
|
|
11435
|
+ pos += escape.length - 1; |
|
|
11436
|
+ continue; |
|
|
11437
|
+ } |
|
|
11438
|
+ } |
|
|
11439
|
+ // Not currently escaping and chr is a quote |
|
|
11440
|
+ // TODO: need to compare bytes instead of single char |
|
|
11441
|
+ if (this.state.commenting === false && this.__isQuote(buf, pos)) { |
|
|
11442
|
+ if (this.state.quoting === true) { |
|
|
11443
|
+ const nextChr = buf[pos + quote.length]; |
|
|
11444
|
+ const isNextChrTrimable = |
|
|
11445
|
+ rtrim && this.__isCharTrimable(buf, pos + quote.length); |
|
|
11446
|
+ const isNextChrComment = |
|
|
11447
|
+ comment !== null && |
|
|
11448
|
+ this.__compareBytes(comment, buf, pos + quote.length, nextChr); |
|
|
11449
|
+ const isNextChrDelimiter = this.__isDelimiter( |
|
|
11450
|
+ buf, |
|
|
11451
|
+ pos + quote.length, |
|
|
11452
|
+ nextChr, |
|
|
11453
|
+ ); |
|
|
11454
|
+ const isNextChrRecordDelimiter = |
|
|
11455
|
+ record_delimiter.length === 0 |
|
|
11456
|
+ ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) |
|
|
11457
|
+ : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); |
|
|
11458
|
+ // Escape a quote |
|
|
11459
|
+ // Treat next char as a regular character |
|
|
11460
|
+ if ( |
|
|
11461
|
+ escape !== null && |
|
|
11462
|
+ this.__isEscape(buf, pos, chr) && |
|
|
11463
|
+ this.__isQuote(buf, pos + escape.length) |
|
|
11464
|
+ ) { |
|
|
11465
|
+ pos += escape.length - 1; |
|
|
11466
|
+ } else if ( |
|
|
11467
|
+ !nextChr || |
|
|
11468
|
+ isNextChrDelimiter || |
|
|
11469
|
+ isNextChrRecordDelimiter || |
|
|
11470
|
+ isNextChrComment || |
|
|
11471
|
+ isNextChrTrimable |
|
|
11472
|
+ ) { |
|
|
11473
|
+ this.state.quoting = false; |
|
|
11474
|
+ this.state.wasQuoting = true; |
|
|
11475
|
+ pos += quote.length - 1; |
|
|
11476
|
+ continue; |
|
|
11477
|
+ } else if (relax_quotes === false) { |
|
|
11478
|
+ const err = this.__error( |
|
|
11479
|
+ new CsvError( |
|
|
11480
|
+ "CSV_INVALID_CLOSING_QUOTE", |
|
|
11481
|
+ [ |
|
|
11482
|
+ "Invalid Closing Quote:", |
|
|
11483
|
+ `got "${String.fromCharCode(nextChr)}"`, |
|
|
11484
|
+ `at line ${this.info.lines}`, |
|
|
11485
|
+ "instead of delimiter, record delimiter, trimable character", |
|
|
11486
|
+ "(if activated) or comment", |
|
|
11487
|
+ ], |
|
|
11488
|
+ this.options, |
|
|
11489
|
+ this.__infoField(), |
|
|
11490
|
+ ), |
|
|
11491
|
+ ); |
|
|
11492
|
+ if (err !== undefined) return err; |
|
|
11493
|
+ } else { |
|
|
11494
|
+ this.state.quoting = false; |
|
|
11495
|
+ this.state.wasQuoting = true; |
|
|
11496
|
+ this.state.field.prepend(quote); |
|
|
11497
|
+ pos += quote.length - 1; |
|
|
11498
|
+ } |
|
|
11499
|
+ } else { |
|
|
11500
|
+ if (this.state.field.length !== 0) { |
|
|
11501
|
+ // In relax_quotes mode, treat opening quote preceded by chrs as regular |
|
|
11502
|
+ if (relax_quotes === false) { |
|
|
11503
|
+ const info = this.__infoField(); |
|
|
11504
|
+ const bom = Object.keys(boms) |
|
|
11505
|
+ .map((b) => |
|
|
11506
|
+ boms[b].equals(this.state.field.toString()) ? b : false, |
|
|
11507
|
+ ) |
|
|
11508
|
+ .filter(Boolean)[0]; |
|
|
11509
|
+ const err = this.__error( |
|
|
11510
|
+ new CsvError( |
|
|
11511
|
+ "INVALID_OPENING_QUOTE", |
|
|
11512
|
+ [ |
|
|
11513
|
+ "Invalid Opening Quote:", |
|
|
11514
|
+ `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, |
|
|
11515
|
+ bom ? `(${bom} bom)` : undefined, |
|
|
11516
|
+ ], |
|
|
11517
|
+ this.options, |
|
|
11518
|
+ info, |
|
|
11519
|
+ { |
|
|
11520
|
+ field: this.state.field, |
|
|
11521
|
+ }, |
|
|
11522
|
+ ), |
|
|
11523
|
+ ); |
|
|
11524
|
+ if (err !== undefined) return err; |
|
|
11525
|
+ } |
|
|
11526
|
+ } else { |
|
|
11527
|
+ this.state.quoting = true; |
|
|
11528
|
+ pos += quote.length - 1; |
|
|
11529
|
+ continue; |
|
|
11530
|
+ } |
|
|
11531
|
+ } |
|
|
11532
|
+ } |
|
|
11533
|
+ if (this.state.quoting === false) { |
|
|
11534
|
+ const recordDelimiterLength = this.__isRecordDelimiter( |
|
|
11535
|
+ chr, |
|
|
11536
|
+ buf, |
|
|
11537
|
+ pos, |
|
|
11538
|
+ ); |
|
|
11539
|
+ if (recordDelimiterLength !== 0) { |
|
|
11540
|
+ // Do not emit comments which take a full line |
|
|
11541
|
+ const skipCommentLine = |
|
|
11542
|
+ this.state.commenting && |
|
|
11543
|
+ this.state.wasQuoting === false && |
|
|
11544
|
+ this.state.record.length === 0 && |
|
|
11545
|
+ this.state.field.length === 0; |
|
|
11546
|
+ if (skipCommentLine) { |
|
|
11547
|
+ this.info.comment_lines++; |
|
|
11548
|
+ // Skip full comment line |
|
|
11549
|
+ } else { |
|
|
11550
|
+ // Activate records emition if above from_line |
|
|
11551
|
+ if ( |
|
|
11552
|
+ this.state.enabled === false && |
|
|
11553
|
+ this.info.lines + |
|
|
11554
|
+ (this.state.wasRowDelimiter === true ? 1 : 0) >= |
|
|
11555
|
+ from_line |
|
|
11556
|
+ ) { |
|
|
11557
|
+ this.state.enabled = true; |
|
|
11558
|
+ this.__resetField(); |
|
|
11559
|
+ this.__resetRecord(); |
|
|
11560
|
+ pos += recordDelimiterLength - 1; |
|
|
11561
|
+ continue; |
|
|
11562
|
+ } |
|
|
11563
|
+ // Skip if line is empty and skip_empty_lines activated |
|
|
11564
|
+ if ( |
|
|
11565
|
+ skip_empty_lines === true && |
|
|
11566
|
+ this.state.wasQuoting === false && |
|
|
11567
|
+ this.state.record.length === 0 && |
|
|
11568
|
+ this.state.field.length === 0 |
|
|
11569
|
+ ) { |
|
|
11570
|
+ this.info.empty_lines++; |
|
|
11571
|
+ pos += recordDelimiterLength - 1; |
|
|
11572
|
+ continue; |
|
|
11573
|
+ } |
|
|
11574
|
+ this.info.bytes = this.state.bufBytesStart + pos; |
|
|
11575
|
+ const errField = this.__onField(); |
|
|
11576
|
+ if (errField !== undefined) return errField; |
|
|
11577
|
+ this.info.bytes = |
|
|
11578
|
+ this.state.bufBytesStart + pos + recordDelimiterLength; |
|
|
11579
|
+ const errRecord = this.__onRecord(push); |
|
|
11580
|
+ if (errRecord !== undefined) return errRecord; |
|
|
11581
|
+ if (to !== -1 && this.info.records >= to) { |
|
|
11582
|
+ this.state.stop = true; |
|
|
11583
|
+ close(); |
|
|
11584
|
+ return; |
|
|
11585
|
+ } |
|
|
11586
|
+ } |
|
|
11587
|
+ this.state.commenting = false; |
|
|
11588
|
+ pos += recordDelimiterLength - 1; |
|
|
11589
|
+ continue; |
|
|
11590
|
+ } |
|
|
11591
|
+ if (this.state.commenting) { |
|
|
11592
|
+ continue; |
|
|
11593
|
+ } |
|
|
11594
|
+ if ( |
|
|
11595
|
+ comment !== null && |
|
|
11596
|
+ (comment_no_infix === false || |
|
|
11597
|
+ (this.state.record.length === 0 && |
|
|
11598
|
+ this.state.field.length === 0)) |
|
|
11599
|
+ ) { |
|
|
11600
|
+ const commentCount = this.__compareBytes(comment, buf, pos, chr); |
|
|
11601
|
+ if (commentCount !== 0) { |
|
|
11602
|
+ this.state.commenting = true; |
|
|
11603
|
+ continue; |
|
|
11604
|
+ } |
|
|
11605
|
+ } |
|
|
11606
|
+ const delimiterLength = this.__isDelimiter(buf, pos, chr); |
|
|
11607
|
+ if (delimiterLength !== 0) { |
|
|
11608
|
+ this.info.bytes = this.state.bufBytesStart + pos; |
|
|
11609
|
+ const errField = this.__onField(); |
|
|
11610
|
+ if (errField !== undefined) return errField; |
|
|
11611
|
+ pos += delimiterLength - 1; |
|
|
11612
|
+ continue; |
|
|
11613
|
+ } |
|
|
11614
|
+ } |
|
|
11615
|
+ } |
|
|
11616
|
+ if (this.state.commenting === false) { |
|
|
11617
|
+ if ( |
|
|
11618
|
+ max_record_size !== 0 && |
|
|
11619
|
+ this.state.record_length + this.state.field.length > max_record_size |
|
|
11620
|
+ ) { |
|
|
11621
|
+ return this.__error( |
|
|
11622
|
+ new CsvError( |
|
|
11623
|
+ "CSV_MAX_RECORD_SIZE", |
|
|
11624
|
+ [ |
|
|
11625
|
+ "Max Record Size:", |
|
|
11626
|
+ "record exceed the maximum number of tolerated bytes", |
|
|
11627
|
+ `of ${max_record_size}`, |
|
|
11628
|
+ `at line ${this.info.lines}`, |
|
|
11629
|
+ ], |
|
|
11630
|
+ this.options, |
|
|
11631
|
+ this.__infoField(), |
|
|
11632
|
+ ), |
|
|
11633
|
+ ); |
|
|
11634
|
+ } |
|
|
11635
|
+ } |
|
|
11636
|
+ const lappend = |
|
|
11637
|
+ ltrim === false || |
|
|
11638
|
+ this.state.quoting === true || |
|
|
11639
|
+ this.state.field.length !== 0 || |
|
|
11640
|
+ !this.__isCharTrimable(buf, pos); |
|
|
11641
|
+ // rtrim in non quoting is handle in __onField |
|
|
11642
|
+ const rappend = rtrim === false || this.state.wasQuoting === false; |
|
|
11643
|
+ if (lappend === true && rappend === true) { |
|
|
11644
|
+ this.state.field.append(chr); |
|
|
11645
|
+ } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { |
|
|
11646
|
+ return this.__error( |
|
|
11647
|
+ new CsvError( |
|
|
11648
|
+ "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", |
|
|
11649
|
+ [ |
|
|
11650
|
+ "Invalid Closing Quote:", |
|
|
11651
|
+ "found non trimable byte after quote", |
|
|
11652
|
+ `at line ${this.info.lines}`, |
|
|
11653
|
+ ], |
|
|
11654
|
+ this.options, |
|
|
11655
|
+ this.__infoField(), |
|
|
11656
|
+ ), |
|
|
11657
|
+ ); |
|
|
11658
|
+ } else { |
|
|
11659
|
+ if (lappend === false) { |
|
|
11660
|
+ pos += this.__isCharTrimable(buf, pos) - 1; |
|
|
11661
|
+ } |
|
|
11662
|
+ continue; |
|
|
11663
|
+ } |
|
|
11664
|
+ } |
|
|
11665
|
+ if (end === true) { |
|
|
11666
|
+ // Ensure we are not ending in a quoting state |
|
|
11667
|
+ if (this.state.quoting === true) { |
|
|
11668
|
+ const err = this.__error( |
|
|
11669
|
+ new CsvError( |
|
|
11670
|
+ "CSV_QUOTE_NOT_CLOSED", |
|
|
11671
|
+ [ |
|
|
11672
|
+ "Quote Not Closed:", |
|
|
11673
|
+ `the parsing is finished with an opening quote at line ${this.info.lines}`, |
|
|
11674
|
+ ], |
|
|
11675
|
+ this.options, |
|
|
11676
|
+ this.__infoField(), |
|
|
11677
|
+ ), |
|
|
11678
|
+ ); |
|
|
11679
|
+ if (err !== undefined) return err; |
|
|
11680
|
+ } else { |
|
|
11681
|
+ // Skip last line if it has no characters |
|
|
11682
|
+ if ( |
|
|
11683
|
+ this.state.wasQuoting === true || |
|
|
11684
|
+ this.state.record.length !== 0 || |
|
|
11685
|
+ this.state.field.length !== 0 |
|
|
11686
|
+ ) { |
|
|
11687
|
+ this.info.bytes = this.state.bufBytesStart + pos; |
|
|
11688
|
+ const errField = this.__onField(); |
|
|
11689
|
+ if (errField !== undefined) return errField; |
|
|
11690
|
+ const errRecord = this.__onRecord(push); |
|
|
11691
|
+ if (errRecord !== undefined) return errRecord; |
|
|
11692
|
+ } else if (this.state.wasRowDelimiter === true) { |
|
|
11693
|
+ this.info.empty_lines++; |
|
|
11694
|
+ } else if (this.state.commenting === true) { |
|
|
11695
|
+ this.info.comment_lines++; |
|
|
11696
|
+ } |
|
|
11697
|
+ } |
|
|
11698
|
+ } else { |
|
|
11699
|
+ this.state.bufBytesStart += pos; |
|
|
11700
|
+ this.state.previousBuf = buf.slice(pos); |
|
|
11701
|
+ } |
|
|
11702
|
+ if (this.state.wasRowDelimiter === true) { |
|
|
11703
|
+ this.info.lines++; |
|
|
11704
|
+ this.state.wasRowDelimiter = false; |
|
|
11705
|
+ } |
|
|
11706
|
+ }, |
|
|
11707
|
+ __onRecord: function (push) { |
|
|
11708
|
+ const { |
|
|
11709
|
+ columns, |
|
|
11710
|
+ group_columns_by_name, |
|
|
11711
|
+ encoding, |
|
|
11712
|
+ info, |
|
|
11713
|
+ from, |
|
|
11714
|
+ relax_column_count, |
|
|
11715
|
+ relax_column_count_less, |
|
|
11716
|
+ relax_column_count_more, |
|
|
11717
|
+ raw, |
|
|
11718
|
+ skip_records_with_empty_values, |
|
|
11719
|
+ } = this.options; |
|
|
11720
|
+ const { enabled, record } = this.state; |
|
|
11721
|
+ if (enabled === false) { |
|
|
11722
|
+ return this.__resetRecord(); |
|
|
11723
|
+ } |
|
|
11724
|
+ // Convert the first line into column names |
|
|
11725
|
+ const recordLength = record.length; |
|
|
11726
|
+ if (columns === true) { |
|
|
11727
|
+ if (skip_records_with_empty_values === true && isRecordEmpty(record)) { |
|
|
11728
|
+ this.__resetRecord(); |
|
|
11729
|
+ return; |
|
|
11730
|
+ } |
|
|
11731
|
+ return this.__firstLineToColumns(record); |
|
|
11732
|
+ } |
|
|
11733
|
+ if (columns === false && this.info.records === 0) { |
|
|
11734
|
+ this.state.expectedRecordLength = recordLength; |
|
|
11735
|
+ } |
|
|
11736
|
+ if (recordLength !== this.state.expectedRecordLength) { |
|
|
11737
|
+ const err = |
|
|
11738
|
+ columns === false |
|
|
11739
|
+ ? new CsvError( |
|
|
11740
|
+ "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", |
|
|
11741
|
+ [ |
|
|
11742
|
+ "Invalid Record Length:", |
|
|
11743
|
+ `expect ${this.state.expectedRecordLength},`, |
|
|
11744
|
+ `got ${recordLength} on line ${this.info.lines}`, |
|
|
11745
|
+ ], |
|
|
11746
|
+ this.options, |
|
|
11747
|
+ this.__infoField(), |
|
|
11748
|
+ { |
|
|
11749
|
+ record: record, |
|
|
11750
|
+ }, |
|
|
11751
|
+ ) |
|
|
11752
|
+ : new CsvError( |
|
|
11753
|
+ "CSV_RECORD_INCONSISTENT_COLUMNS", |
|
|
11754
|
+ [ |
|
|
11755
|
+ "Invalid Record Length:", |
|
|
11756
|
+ `columns length is ${columns.length},`, // rename columns |
|
|
11757
|
+ `got ${recordLength} on line ${this.info.lines}`, |
|
|
11758
|
+ ], |
|
|
11759
|
+ this.options, |
|
|
11760
|
+ this.__infoField(), |
|
|
11761
|
+ { |
|
|
11762
|
+ record: record, |
|
|
11763
|
+ }, |
|
|
11764
|
+ ); |
|
|
11765
|
+ if ( |
|
|
11766
|
+ relax_column_count === true || |
|
|
11767
|
+ (relax_column_count_less === true && |
|
|
11768
|
+ recordLength < this.state.expectedRecordLength) || |
|
|
11769
|
+ (relax_column_count_more === true && |
|
|
11770
|
+ recordLength > this.state.expectedRecordLength) |
|
|
11771
|
+ ) { |
|
|
11772
|
+ this.info.invalid_field_length++; |
|
|
11773
|
+ this.state.error = err; |
|
|
11774
|
+ // Error is undefined with skip_records_with_error |
|
|
11775
|
+ } else { |
|
|
11776
|
+ const finalErr = this.__error(err); |
|
|
11777
|
+ if (finalErr) return finalErr; |
|
|
11778
|
+ } |
|
|
11779
|
+ } |
|
|
11780
|
+ if (skip_records_with_empty_values === true && isRecordEmpty(record)) { |
|
|
11781
|
+ this.__resetRecord(); |
|
|
11782
|
+ return; |
|
|
11783
|
+ } |
|
|
11784
|
+ if (this.state.recordHasError === true) { |
|
|
11785
|
+ this.__resetRecord(); |
|
|
11786
|
+ this.state.recordHasError = false; |
|
|
11787
|
+ return; |
|
|
11788
|
+ } |
|
|
11789
|
+ this.info.records++; |
|
|
11790
|
+ if (from === 1 || this.info.records >= from) { |
|
|
11791
|
+ const { objname } = this.options; |
|
|
11792
|
+ // With columns, records are object |
|
|
11793
|
+ if (columns !== false) { |
|
|
11794
|
+ const obj = {}; |
|
|
11795
|
+ // Transform record array to an object |
|
|
11796
|
+ for (let i = 0, l = record.length; i < l; i++) { |
|
|
11797
|
+ if (columns[i] === undefined || columns[i].disabled) continue; |
|
|
11798
|
+ // Turn duplicate columns into an array |
|
|
11799
|
+ if ( |
|
|
11800
|
+ group_columns_by_name === true && |
|
|
11801
|
+ obj[columns[i].name] !== undefined |
|
|
11802
|
+ ) { |
|
|
11803
|
+ if (Array.isArray(obj[columns[i].name])) { |
|
|
11804
|
+ obj[columns[i].name] = obj[columns[i].name].concat(record[i]); |
|
|
11805
|
+ } else { |
|
|
11806
|
+ obj[columns[i].name] = [obj[columns[i].name], record[i]]; |
|
|
11807
|
+ } |
|
|
11808
|
+ } else { |
|
|
11809
|
+ obj[columns[i].name] = record[i]; |
|
|
11810
|
+ } |
|
|
11811
|
+ } |
|
|
11812
|
+ // Without objname (default) |
|
|
11813
|
+ if (raw === true || info === true) { |
|
|
11814
|
+ const extRecord = Object.assign( |
|
|
11815
|
+ { record: obj }, |
|
|
11816
|
+ raw === true |
|
|
11817
|
+ ? { raw: this.state.rawBuffer.toString(encoding) } |
|
|
11818
|
+ : {}, |
|
|
11819
|
+ info === true ? { info: this.__infoRecord() } : {}, |
|
|
11820
|
+ ); |
|
|
11821
|
+ const err = this.__push( |
|
|
11822
|
+ objname === undefined ? extRecord : [obj[objname], extRecord], |
|
|
11823
|
+ push, |
|
|
11824
|
+ ); |
|
|
11825
|
+ if (err) { |
|
|
11826
|
+ return err; |
|
|
11827
|
+ } |
|
|
11828
|
+ } else { |
|
|
11829
|
+ const err = this.__push( |
|
|
11830
|
+ objname === undefined ? obj : [obj[objname], obj], |
|
|
11831
|
+ push, |
|
|
11832
|
+ ); |
|
|
11833
|
+ if (err) { |
|
|
11834
|
+ return err; |
|
|
11835
|
+ } |
|
|
11836
|
+ } |
|
|
11837
|
+ // Without columns, records are array |
|
|
11838
|
+ } else { |
|
|
11839
|
+ if (raw === true || info === true) { |
|
|
11840
|
+ const extRecord = Object.assign( |
|
|
11841
|
+ { record: record }, |
|
|
11842
|
+ raw === true |
|
|
11843
|
+ ? { raw: this.state.rawBuffer.toString(encoding) } |
|
|
11844
|
+ : {}, |
|
|
11845
|
+ info === true ? { info: this.__infoRecord() } : {}, |
|
|
11846
|
+ ); |
|
|
11847
|
+ const err = this.__push( |
|
|
11848
|
+ objname === undefined ? extRecord : [record[objname], extRecord], |
|
|
11849
|
+ push, |
|
|
11850
|
+ ); |
|
|
11851
|
+ if (err) { |
|
|
11852
|
+ return err; |
|
|
11853
|
+ } |
|
|
11854
|
+ } else { |
|
|
11855
|
+ const err = this.__push( |
|
|
11856
|
+ objname === undefined ? record : [record[objname], record], |
|
|
11857
|
+ push, |
|
|
11858
|
+ ); |
|
|
11859
|
+ if (err) { |
|
|
11860
|
+ return err; |
|
|
11861
|
+ } |
|
|
11862
|
+ } |
|
|
11863
|
+ } |
|
|
11864
|
+ } |
|
|
11865
|
+ this.__resetRecord(); |
|
|
11866
|
+ }, |
|
|
11867
|
+ __firstLineToColumns: function (record) { |
|
|
11868
|
+ const { firstLineToHeaders } = this.state; |
|
|
11869
|
+ try { |
|
|
11870
|
+ const headers = |
|
|
11871
|
+ firstLineToHeaders === undefined |
|
|
11872
|
+ ? record |
|
|
11873
|
+ : firstLineToHeaders.call(null, record); |
|
|
11874
|
+ if (!Array.isArray(headers)) { |
|
|
11875
|
+ return this.__error( |
|
|
11876
|
+ new CsvError( |
|
|
11877
|
+ "CSV_INVALID_COLUMN_MAPPING", |
|
|
11878
|
+ [ |
|
|
11879
|
+ "Invalid Column Mapping:", |
|
|
11880
|
+ "expect an array from column function,", |
|
|
11881
|
+ `got ${JSON.stringify(headers)}`, |
|
|
11882
|
+ ], |
|
|
11883
|
+ this.options, |
|
|
11884
|
+ this.__infoField(), |
|
|
11885
|
+ { |
|
|
11886
|
+ headers: headers, |
|
|
11887
|
+ }, |
|
|
11888
|
+ ), |
|
|
11889
|
+ ); |
|
|
11890
|
+ } |
|
|
11891
|
+ const normalizedHeaders = normalize_columns_array(headers); |
|
|
11892
|
+ this.state.expectedRecordLength = normalizedHeaders.length; |
|
|
11893
|
+ this.options.columns = normalizedHeaders; |
|
|
11894
|
+ this.__resetRecord(); |
|
|
11895
|
+ return; |
|
|
11896
|
+ } catch (err) { |
|
|
11897
|
+ return err; |
|
|
11898
|
+ } |
|
|
11899
|
+ }, |
|
|
11900
|
+ __resetRecord: function () { |
|
|
11901
|
+ if (this.options.raw === true) { |
|
|
11902
|
+ this.state.rawBuffer.reset(); |
|
|
11903
|
+ } |
|
|
11904
|
+ this.state.error = undefined; |
|
|
11905
|
+ this.state.record = []; |
|
|
11906
|
+ this.state.record_length = 0; |
|
|
11907
|
+ }, |
|
|
11908
|
+ __onField: function () { |
|
|
11909
|
+ const { cast, encoding, rtrim, max_record_size } = this.options; |
|
|
11910
|
+ const { enabled, wasQuoting } = this.state; |
|
|
11911
|
+ // Short circuit for the from_line options |
|
|
11912
|
+ if (enabled === false) { |
|
|
11913
|
+ return this.__resetField(); |
|
|
11914
|
+ } |
|
|
11915
|
+ let field = this.state.field.toString(encoding); |
|
|
11916
|
+ if (rtrim === true && wasQuoting === false) { |
|
|
11917
|
+ field = field.trimRight(); |
|
|
11918
|
+ } |
|
|
11919
|
+ if (cast === true) { |
|
|
11920
|
+ const [err, f] = this.__cast(field); |
|
|
11921
|
+ if (err !== undefined) return err; |
|
|
11922
|
+ field = f; |
|
|
11923
|
+ } |
|
|
11924
|
+ this.state.record.push(field); |
|
|
11925
|
+ // Increment record length if record size must not exceed a limit |
|
|
11926
|
+ if (max_record_size !== 0 && typeof field === "string") { |
|
|
11927
|
+ this.state.record_length += field.length; |
|
|
11928
|
+ } |
|
|
11929
|
+ this.__resetField(); |
|
|
11930
|
+ }, |
|
|
11931
|
+ __resetField: function () { |
|
|
11932
|
+ this.state.field.reset(); |
|
|
11933
|
+ this.state.wasQuoting = false; |
|
|
11934
|
+ }, |
|
|
11935
|
+ __push: function (record, push) { |
|
|
11936
|
+ const { on_record } = this.options; |
|
|
11937
|
+ if (on_record !== undefined) { |
|
|
11938
|
+ const info = this.__infoRecord(); |
|
|
11939
|
+ try { |
|
|
11940
|
+ record = on_record.call(null, record, info); |
|
|
11941
|
+ } catch (err) { |
|
|
11942
|
+ return err; |
|
|
11943
|
+ } |
|
|
11944
|
+ if (record === undefined || record === null) { |
|
|
11945
|
+ return; |
|
|
11946
|
+ } |
|
|
11947
|
+ } |
|
|
11948
|
+ push(record); |
|
|
11949
|
+ }, |
|
|
11950
|
+ // Return a tuple with the error and the casted value |
|
|
11951
|
+ __cast: function (field) { |
|
|
11952
|
+ const { columns, relax_column_count } = this.options; |
|
|
11953
|
+ const isColumns = Array.isArray(columns); |
|
|
11954
|
+ // Dont loose time calling cast |
|
|
11955
|
+ // because the final record is an object |
|
|
11956
|
+ // and this field can't be associated to a key present in columns |
|
|
11957
|
+ if ( |
|
|
11958
|
+ isColumns === true && |
|
|
11959
|
+ relax_column_count && |
|
|
11960
|
+ this.options.columns.length <= this.state.record.length |
|
|
11961
|
+ ) { |
|
|
11962
|
+ return [undefined, undefined]; |
|
|
11963
|
+ } |
|
|
11964
|
+ if (this.state.castField !== null) { |
|
|
11965
|
+ try { |
|
|
11966
|
+ const info = this.__infoField(); |
|
|
11967
|
+ return [undefined, this.state.castField.call(null, field, info)]; |
|
|
11968
|
+ } catch (err) { |
|
|
11969
|
+ return [err]; |
|
|
11970
|
+ } |
|
|
11971
|
+ } |
|
|
11972
|
+ if (this.__isFloat(field)) { |
|
|
11973
|
+ return [undefined, parseFloat(field)]; |
|
|
11974
|
+ } else if (this.options.cast_date !== false) { |
|
|
11975
|
+ const info = this.__infoField(); |
|
|
11976
|
+ return [undefined, this.options.cast_date.call(null, field, info)]; |
|
|
11977
|
+ } |
|
|
11978
|
+ return [undefined, field]; |
|
|
11979
|
+ }, |
|
|
11980
|
+ // Helper to test if a character is a space or a line delimiter |
|
|
11981
|
+ __isCharTrimable: function (buf, pos) { |
|
|
11982
|
+ const isTrim = (buf, pos) => { |
|
|
11983
|
+ const { timchars } = this.state; |
|
|
11984
|
+ loop1: for (let i = 0; i < timchars.length; i++) { |
|
|
11985
|
+ const timchar = timchars[i]; |
|
|
11986
|
+ for (let j = 0; j < timchar.length; j++) { |
|
|
11987
|
+ if (timchar[j] !== buf[pos + j]) continue loop1; |
|
|
11988
|
+ } |
|
|
11989
|
+ return timchar.length; |
|
|
11990
|
+ } |
|
|
11991
|
+ return 0; |
|
|
11992
|
+ }; |
|
|
11993
|
+ return isTrim(buf, pos); |
|
|
11994
|
+ }, |
|
|
11995
|
+ // Keep it in case we implement the `cast_int` option |
|
|
11996
|
+ // __isInt(value){ |
|
|
11997
|
+ // // return Number.isInteger(parseInt(value)) |
|
|
11998
|
+ // // return !isNaN( parseInt( obj ) ); |
|
|
11999
|
+ // return /^(\-|\+)?[1-9][0-9]*$/.test(value) |
|
|
12000
|
+ // } |
|
|
12001
|
+ __isFloat: function (value) { |
|
|
12002
|
+ return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery |
|
|
12003
|
+ }, |
|
|
12004
|
+ __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { |
|
|
12005
|
+ if (sourceBuf[0] !== firstByte) return 0; |
|
|
12006
|
+ const sourceLength = sourceBuf.length; |
|
|
12007
|
+ for (let i = 1; i < sourceLength; i++) { |
|
|
12008
|
+ if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; |
|
|
12009
|
+ } |
|
|
12010
|
+ return sourceLength; |
|
|
12011
|
+ }, |
|
|
12012
|
+ __isDelimiter: function (buf, pos, chr) { |
|
|
12013
|
+ const { delimiter, ignore_last_delimiters } = this.options; |
|
|
12014
|
+ if ( |
|
|
12015
|
+ ignore_last_delimiters === true && |
|
|
12016
|
+ this.state.record.length === this.options.columns.length - 1 |
|
|
12017
|
+ ) { |
|
|
12018
|
+ return 0; |
|
|
12019
|
+ } else if ( |
|
|
12020
|
+ ignore_last_delimiters !== false && |
|
|
12021
|
+ typeof ignore_last_delimiters === "number" && |
|
|
12022
|
+ this.state.record.length === ignore_last_delimiters - 1 |
|
|
12023
|
+ ) { |
|
|
12024
|
+ return 0; |
|
|
12025
|
+ } |
|
|
12026
|
+ loop1: for (let i = 0; i < delimiter.length; i++) { |
|
|
12027
|
+ const del = delimiter[i]; |
|
|
12028
|
+ if (del[0] === chr) { |
|
|
12029
|
+ for (let j = 1; j < del.length; j++) { |
|
|
12030
|
+ if (del[j] !== buf[pos + j]) continue loop1; |
|
|
12031
|
+ } |
|
|
12032
|
+ return del.length; |
|
|
12033
|
+ } |
|
|
12034
|
+ } |
|
|
12035
|
+ return 0; |
|
|
12036
|
+ }, |
|
|
12037
|
+ __isRecordDelimiter: function (chr, buf, pos) { |
|
|
12038
|
+ const { record_delimiter } = this.options; |
|
|
12039
|
+ const recordDelimiterLength = record_delimiter.length; |
|
|
12040
|
+ loop1: for (let i = 0; i < recordDelimiterLength; i++) { |
|
|
12041
|
+ const rd = record_delimiter[i]; |
|
|
12042
|
+ const rdLength = rd.length; |
|
|
12043
|
+ if (rd[0] !== chr) { |
|
|
12044
|
+ continue; |
|
|
12045
|
+ } |
|
|
12046
|
+ for (let j = 1; j < rdLength; j++) { |
|
|
12047
|
+ if (rd[j] !== buf[pos + j]) { |
|
|
12048
|
+ continue loop1; |
|
|
12049
|
+ } |
|
|
12050
|
+ } |
|
|
12051
|
+ return rd.length; |
|
|
12052
|
+ } |
|
|
12053
|
+ return 0; |
|
|
12054
|
+ }, |
|
|
12055
|
+ __isEscape: function (buf, pos, chr) { |
|
|
12056
|
+ const { escape } = this.options; |
|
|
12057
|
+ if (escape === null) return false; |
|
|
12058
|
+ const l = escape.length; |
|
|
12059
|
+ if (escape[0] === chr) { |
|
|
12060
|
+ for (let i = 0; i < l; i++) { |
|
|
12061
|
+ if (escape[i] !== buf[pos + i]) { |
|
|
12062
|
+ return false; |
|
|
12063
|
+ } |
|
|
12064
|
+ } |
|
|
12065
|
+ return true; |
|
|
12066
|
+ } |
|
|
12067
|
+ return false; |
|
|
12068
|
+ }, |
|
|
12069
|
+ __isQuote: function (buf, pos) { |
|
|
12070
|
+ const { quote } = this.options; |
|
|
12071
|
+ if (quote === null) return false; |
|
|
12072
|
+ const l = quote.length; |
|
|
12073
|
+ for (let i = 0; i < l; i++) { |
|
|
12074
|
+ if (quote[i] !== buf[pos + i]) { |
|
|
12075
|
+ return false; |
|
|
12076
|
+ } |
|
|
12077
|
+ } |
|
|
12078
|
+ return true; |
|
|
12079
|
+ }, |
|
|
12080
|
+ __autoDiscoverRecordDelimiter: function (buf, pos) { |
|
|
12081
|
+ const { encoding } = this.options; |
|
|
12082
|
+ // Note, we don't need to cache this information in state, |
|
|
12083
|
+ // It is only called on the first line until we find out a suitable |
|
|
12084
|
+ // record delimiter. |
|
|
12085
|
+ const rds = [ |
|
|
12086
|
+ // Important, the windows line ending must be before mac os 9 |
|
|
12087
|
+ Buffer.from("\r\n", encoding), |
|
|
12088
|
+ Buffer.from("\n", encoding), |
|
|
12089
|
+ Buffer.from("\r", encoding), |
|
|
12090
|
+ ]; |
|
|
12091
|
+ loop: for (let i = 0; i < rds.length; i++) { |
|
|
12092
|
+ const l = rds[i].length; |
|
|
12093
|
+ for (let j = 0; j < l; j++) { |
|
|
12094
|
+ if (rds[i][j] !== buf[pos + j]) { |
|
|
12095
|
+ continue loop; |
|
|
12096
|
+ } |
|
|
12097
|
+ } |
|
|
12098
|
+ this.options.record_delimiter.push(rds[i]); |
|
|
12099
|
+ this.state.recordDelimiterMaxLength = rds[i].length; |
|
|
12100
|
+ return rds[i].length; |
|
|
12101
|
+ } |
|
|
12102
|
+ return 0; |
|
|
12103
|
+ }, |
|
|
12104
|
+ __error: function (msg) { |
|
|
12105
|
+ const { encoding, raw, skip_records_with_error } = this.options; |
|
|
12106
|
+ const err = typeof msg === "string" ? new Error(msg) : msg; |
|
|
12107
|
+ if (skip_records_with_error) { |
|
|
12108
|
+ this.state.recordHasError = true; |
|
|
12109
|
+ if (this.options.on_skip !== undefined) { |
|
|
12110
|
+ this.options.on_skip( |
|
|
12111
|
+ err, |
|
|
12112
|
+ raw ? this.state.rawBuffer.toString(encoding) : undefined, |
|
|
12113
|
+ ); |
|
|
12114
|
+ } |
|
|
12115
|
+ // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); |
|
|
12116
|
+ return undefined; |
|
|
12117
|
+ } else { |
|
|
12118
|
+ return err; |
|
|
12119
|
+ } |
|
|
12120
|
+ }, |
|
|
12121
|
+ __infoDataSet: function () { |
|
|
12122
|
+ return { |
|
|
12123
|
+ ...this.info, |
|
|
12124
|
+ columns: this.options.columns, |
|
|
12125
|
+ }; |
|
|
12126
|
+ }, |
|
|
12127
|
+ __infoRecord: function () { |
|
|
12128
|
+ const { columns, raw, encoding } = this.options; |
|
|
12129
|
+ return { |
|
|
12130
|
+ ...this.__infoDataSet(), |
|
|
12131
|
+ error: this.state.error, |
|
|
12132
|
+ header: columns === true, |
|
|
12133
|
+ index: this.state.record.length, |
|
|
12134
|
+ raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, |
|
|
12135
|
+ }; |
|
|
12136
|
+ }, |
|
|
12137
|
+ __infoField: function () { |
|
|
12138
|
+ const { columns } = this.options; |
|
|
12139
|
+ const isColumns = Array.isArray(columns); |
|
|
12140
|
+ return { |
|
|
12141
|
+ ...this.__infoRecord(), |
|
|
12142
|
+ column: |
|
|
12143
|
+ isColumns === true |
|
|
12144
|
+ ? columns.length > this.state.record.length |
|
|
12145
|
+ ? columns[this.state.record.length].name |
|
|
12146
|
+ : null |
|
|
12147
|
+ : this.state.record.length, |
|
|
12148
|
+ quoting: this.state.wasQuoting, |
|
|
12149
|
+ }; |
|
|
12150
|
+ }, |
|
|
12151
|
+ }; |
|
|
12152
|
+}; |
|
|
12153
|
+ |
|
|
12154
|
+const parse = function (data, opts = {}) { |
|
|
12155
|
+ if (typeof data === "string") { |
|
|
12156
|
+ data = Buffer.from(data); |
|
|
12157
|
+ } |
|
|
12158
|
+ const records = opts && opts.objname ? {} : []; |
|
|
12159
|
+ const parser = transform(opts); |
|
|
12160
|
+ const push = (record) => { |
|
|
12161
|
+ if (parser.options.objname === undefined) records.push(record); |
|
|
12162
|
+ else { |
|
|
12163
|
+ records[record[0]] = record[1]; |
|
|
12164
|
+ } |
|
|
12165
|
+ }; |
|
|
12166
|
+ const close = () => {}; |
|
|
12167
|
+ const err1 = parser.parse(data, false, push, close); |
|
|
12168
|
+ if (err1 !== undefined) throw err1; |
|
|
12169
|
+ const err2 = parser.parse(undefined, true, push, close); |
|
|
12170
|
+ if (err2 !== undefined) throw err2; |
|
|
12171
|
+ return records; |
|
|
12172
|
+}; |
|
|
12173
|
+ |
|
|
12174
|
+exports.CsvError = CsvError; |
|
|
12175
|
+exports.parse = parse; |
|
|
12176
|
+ |
|
|
12177
|
+ |
|
10336
|
12178
|
/***/ }) |
|
10337
|
12179
|
|
|
10338
|
12180
|
/******/ }); |