@contrail/cli 3.4.4-alpha.7adb62a → 3.4.4-alpha.9fbce6b

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.
Files changed (36) hide show
  1. package/README.md +1 -1
  2. package/node_modules/@contrail/loader/README.md +0 -0
  3. package/node_modules/@contrail/loader/lib/index.d.ts +941 -0
  4. package/node_modules/@contrail/loader/lib/index.js +12492 -0
  5. package/node_modules/@contrail/loader/lib/index.js.map +1 -0
  6. package/node_modules/@contrail/loader/package.json +70 -0
  7. package/node_modules/csv-parse/LICENSE +21 -0
  8. package/node_modules/csv-parse/README.md +86 -0
  9. package/node_modules/csv-parse/dist/cjs/index.cjs +1424 -0
  10. package/node_modules/csv-parse/dist/cjs/index.d.cts +283 -0
  11. package/node_modules/csv-parse/dist/cjs/sync.cjs +1336 -0
  12. package/node_modules/csv-parse/dist/cjs/sync.d.cts +11 -0
  13. package/node_modules/csv-parse/dist/esm/index.d.ts +283 -0
  14. package/node_modules/csv-parse/dist/esm/index.js +6544 -0
  15. package/node_modules/csv-parse/dist/esm/sync.d.ts +11 -0
  16. package/node_modules/csv-parse/dist/esm/sync.js +3305 -0
  17. package/node_modules/csv-parse/dist/iife/index.js +6553 -0
  18. package/node_modules/csv-parse/dist/iife/sync.js +3313 -0
  19. package/node_modules/csv-parse/dist/umd/index.js +6554 -0
  20. package/node_modules/csv-parse/dist/umd/sync.js +3314 -0
  21. package/node_modules/csv-parse/lib/api/CsvError.js +19 -0
  22. package/node_modules/csv-parse/lib/api/index.js +729 -0
  23. package/node_modules/csv-parse/lib/api/init_state.js +58 -0
  24. package/node_modules/csv-parse/lib/api/normalize_columns_array.js +33 -0
  25. package/node_modules/csv-parse/lib/api/normalize_options.js +448 -0
  26. package/node_modules/csv-parse/lib/index.d.ts +283 -0
  27. package/node_modules/csv-parse/lib/index.js +121 -0
  28. package/node_modules/csv-parse/lib/stream.js +27 -0
  29. package/node_modules/csv-parse/lib/sync.d.ts +11 -0
  30. package/node_modules/csv-parse/lib/sync.js +27 -0
  31. package/node_modules/csv-parse/lib/utils/ResizeableBuffer.js +64 -0
  32. package/node_modules/csv-parse/lib/utils/is_object.js +6 -0
  33. package/node_modules/csv-parse/lib/utils/underscore.js +8 -0
  34. package/node_modules/csv-parse/package.json +142 -0
  35. package/oclif.manifest.json +1 -1
  36. package/package.json +3 -1
@@ -0,0 +1,729 @@
1
+
2
+ import {normalize_columns_array} from './normalize_columns_array.js';
3
+ import {init_state} from './init_state.js';
4
+ import {normalize_options} from './normalize_options.js';
5
+ import {CsvError} from './CsvError.js';
6
+
7
+ const isRecordEmpty = function(record){
8
+ return record.every((field) => field == null || field.toString && field.toString().trim() === '');
9
+ };
10
+
11
+ const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal
12
+ const nl = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal
13
+
14
+ const boms = {
15
+ // Note, the following are equals:
16
+ // Buffer.from("\ufeff")
17
+ // Buffer.from([239, 187, 191])
18
+ // Buffer.from('EFBBBF', 'hex')
19
+ 'utf8': Buffer.from([239, 187, 191]),
20
+ // Note, the following are equals:
21
+ // Buffer.from "\ufeff", 'utf16le
22
+ // Buffer.from([255, 254])
23
+ 'utf16le': Buffer.from([255, 254])
24
+ };
25
+
26
+ const transform = function(original_options = {}) {
27
+ const info = {
28
+ bytes: 0,
29
+ comment_lines: 0,
30
+ empty_lines: 0,
31
+ invalid_field_length: 0,
32
+ lines: 1,
33
+ records: 0
34
+ };
35
+ const options = normalize_options(original_options);
36
+ return {
37
+ info: info,
38
+ original_options: original_options,
39
+ options: options,
40
+ state: init_state(options),
41
+ __needMoreData: function(i, bufLen, end){
42
+ if(end) return false;
43
+ const {encoding, escape, quote} = this.options;
44
+ const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state;
45
+ const numOfCharLeft = bufLen - i - 1;
46
+ const requiredLength = Math.max(
47
+ needMoreDataSize,
48
+ // Skip if the remaining buffer smaller than record delimiter
49
+ // If "record_delimiter" is yet to be discovered:
50
+ // 1. It is equals to `[]` and "recordDelimiterMaxLength" equals `0`
51
+ // 2. We set the length to windows line ending in the current encoding
52
+ // Note, that encoding is known from user or bom discovery at that point
53
+ // recordDelimiterMaxLength,
54
+ recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength,
55
+ // Skip if remaining buffer can be an escaped quote
56
+ quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0,
57
+ // Skip if remaining buffer can be record delimiter following the closing quote
58
+ quoting ? (quote.length + recordDelimiterMaxLength) : 0,
59
+ );
60
+ return numOfCharLeft < requiredLength;
61
+ },
62
+ // Central parser implementation
63
+ parse: function(nextBuf, end, push, close){
64
+ const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options;
65
+ let {comment, escape, quote, record_delimiter} = this.options;
66
+ const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state;
67
+ let buf;
68
+ if(previousBuf === undefined){
69
+ if(nextBuf === undefined){
70
+ // Handle empty string
71
+ close();
72
+ return;
73
+ }else{
74
+ buf = nextBuf;
75
+ }
76
+ }else if(previousBuf !== undefined && nextBuf === undefined){
77
+ buf = previousBuf;
78
+ }else{
79
+ buf = Buffer.concat([previousBuf, nextBuf]);
80
+ }
81
+ // Handle UTF BOM
82
+ if(bomSkipped === false){
83
+ if(bom === false){
84
+ this.state.bomSkipped = true;
85
+ }else if(buf.length < 3){
86
+ // No enough data
87
+ if(end === false){
88
+ // Wait for more data
89
+ this.state.previousBuf = buf;
90
+ return;
91
+ }
92
+ }else{
93
+ for(const encoding in boms){
94
+ if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){
95
+ // Skip BOM
96
+ const bomLength = boms[encoding].length;
97
+ this.state.bufBytesStart += bomLength;
98
+ buf = buf.slice(bomLength);
99
+ // Renormalize original options with the new encoding
100
+ this.options = normalize_options({...this.original_options, encoding: encoding});
101
+ // Options will re-evaluate the Buffer with the new encoding
102
+ ({comment, escape, quote } = this.options);
103
+ break;
104
+ }
105
+ }
106
+ this.state.bomSkipped = true;
107
+ }
108
+ }
109
+ const bufLen = buf.length;
110
+ let pos;
111
+ for(pos = 0; pos < bufLen; pos++){
112
+ // Ensure we get enough space to look ahead
113
+ // There should be a way to move this out of the loop
114
+ if(this.__needMoreData(pos, bufLen, end)){
115
+ break;
116
+ }
117
+ if(this.state.wasRowDelimiter === true){
118
+ this.info.lines++;
119
+ this.state.wasRowDelimiter = false;
120
+ }
121
+ if(to_line !== -1 && this.info.lines > to_line){
122
+ this.state.stop = true;
123
+ close();
124
+ return;
125
+ }
126
+ // Auto discovery of record_delimiter, unix, mac and windows supported
127
+ if(this.state.quoting === false && record_delimiter.length === 0){
128
+ const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos);
129
+ if(record_delimiterCount){
130
+ record_delimiter = this.options.record_delimiter;
131
+ }
132
+ }
133
+ const chr = buf[pos];
134
+ if(raw === true){
135
+ rawBuffer.append(chr);
136
+ }
137
+ if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){
138
+ this.state.wasRowDelimiter = true;
139
+ }
140
+ // Previous char was a valid escape char
141
+ // treat the current char as a regular char
142
+ if(this.state.escaping === true){
143
+ this.state.escaping = false;
144
+ }else{
145
+ // Escape is only active inside quoted fields
146
+ // We are quoting, the char is an escape chr and there is a chr to escape
147
+ // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){
148
+ if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){
149
+ if(escapeIsQuote){
150
+ if(this.__isQuote(buf, pos+escape.length)){
151
+ this.state.escaping = true;
152
+ pos += escape.length - 1;
153
+ continue;
154
+ }
155
+ }else{
156
+ this.state.escaping = true;
157
+ pos += escape.length - 1;
158
+ continue;
159
+ }
160
+ }
161
+ // Not currently escaping and chr is a quote
162
+ // TODO: need to compare bytes instead of single char
163
+ if(this.state.commenting === false && this.__isQuote(buf, pos)){
164
+ if(this.state.quoting === true){
165
+ const nextChr = buf[pos+quote.length];
166
+ const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length);
167
+ const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr);
168
+ const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr);
169
+ const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length);
170
+ // Escape a quote
171
+ // Treat next char as a regular character
172
+ if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){
173
+ pos += escape.length - 1;
174
+ }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){
175
+ this.state.quoting = false;
176
+ this.state.wasQuoting = true;
177
+ pos += quote.length - 1;
178
+ continue;
179
+ }else if(relax_quotes === false){
180
+ const err = this.__error(
181
+ new CsvError('CSV_INVALID_CLOSING_QUOTE', [
182
+ 'Invalid Closing Quote:',
183
+ `got "${String.fromCharCode(nextChr)}"`,
184
+ `at line ${this.info.lines}`,
185
+ 'instead of delimiter, record delimiter, trimable character',
186
+ '(if activated) or comment',
187
+ ], this.options, this.__infoField())
188
+ );
189
+ if(err !== undefined) return err;
190
+ }else{
191
+ this.state.quoting = false;
192
+ this.state.wasQuoting = true;
193
+ this.state.field.prepend(quote);
194
+ pos += quote.length - 1;
195
+ }
196
+ }else{
197
+ if(this.state.field.length !== 0){
198
+ // In relax_quotes mode, treat opening quote preceded by chrs as regular
199
+ if(relax_quotes === false){
200
+ const info = this.__infoField();
201
+ const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0];
202
+ const err = this.__error(
203
+ new CsvError('INVALID_OPENING_QUOTE', [
204
+ 'Invalid Opening Quote:',
205
+ `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`,
206
+ bom ? `(${bom} bom)` : undefined
207
+ ], this.options, info, {
208
+ field: this.state.field,
209
+ })
210
+ );
211
+ if(err !== undefined) return err;
212
+ }
213
+ }else{
214
+ this.state.quoting = true;
215
+ pos += quote.length - 1;
216
+ continue;
217
+ }
218
+ }
219
+ }
220
+ if(this.state.quoting === false){
221
+ const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos);
222
+ if(recordDelimiterLength !== 0){
223
+ // Do not emit comments which take a full line
224
+ const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0);
225
+ if(skipCommentLine){
226
+ this.info.comment_lines++;
227
+ // Skip full comment line
228
+ }else{
229
+ // Activate records emition if above from_line
230
+ if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){
231
+ this.state.enabled = true;
232
+ this.__resetField();
233
+ this.__resetRecord();
234
+ pos += recordDelimiterLength - 1;
235
+ continue;
236
+ }
237
+ // Skip if line is empty and skip_empty_lines activated
238
+ if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){
239
+ this.info.empty_lines++;
240
+ pos += recordDelimiterLength - 1;
241
+ continue;
242
+ }
243
+ this.info.bytes = this.state.bufBytesStart + pos;
244
+ const errField = this.__onField();
245
+ if(errField !== undefined) return errField;
246
+ this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength;
247
+ const errRecord = this.__onRecord(push);
248
+ if(errRecord !== undefined) return errRecord;
249
+ if(to !== -1 && this.info.records >= to){
250
+ this.state.stop = true;
251
+ close();
252
+ return;
253
+ }
254
+ }
255
+ this.state.commenting = false;
256
+ pos += recordDelimiterLength - 1;
257
+ continue;
258
+ }
259
+ if(this.state.commenting){
260
+ continue;
261
+ }
262
+ if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) {
263
+ const commentCount = this.__compareBytes(comment, buf, pos, chr);
264
+ if(commentCount !== 0){
265
+ this.state.commenting = true;
266
+ continue;
267
+ }
268
+ }
269
+ const delimiterLength = this.__isDelimiter(buf, pos, chr);
270
+ if(delimiterLength !== 0){
271
+ this.info.bytes = this.state.bufBytesStart + pos;
272
+ const errField = this.__onField();
273
+ if(errField !== undefined) return errField;
274
+ pos += delimiterLength - 1;
275
+ continue;
276
+ }
277
+ }
278
+ }
279
+ if(this.state.commenting === false){
280
+ if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){
281
+ return this.__error(
282
+ new CsvError('CSV_MAX_RECORD_SIZE', [
283
+ 'Max Record Size:',
284
+ 'record exceed the maximum number of tolerated bytes',
285
+ `of ${max_record_size}`,
286
+ `at line ${this.info.lines}`,
287
+ ], this.options, this.__infoField())
288
+ );
289
+ }
290
+ }
291
+ const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos);
292
+ // rtrim in non quoting is handle in __onField
293
+ const rappend = rtrim === false || this.state.wasQuoting === false;
294
+ if(lappend === true && rappend === true){
295
+ this.state.field.append(chr);
296
+ }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){
297
+ return this.__error(
298
+ new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [
299
+ 'Invalid Closing Quote:',
300
+ 'found non trimable byte after quote',
301
+ `at line ${this.info.lines}`,
302
+ ], this.options, this.__infoField())
303
+ );
304
+ }else{
305
+ if(lappend === false){
306
+ pos += this.__isCharTrimable(buf, pos) - 1;
307
+ }
308
+ continue;
309
+ }
310
+ }
311
+ if(end === true){
312
+ // Ensure we are not ending in a quoting state
313
+ if(this.state.quoting === true){
314
+ const err = this.__error(
315
+ new CsvError('CSV_QUOTE_NOT_CLOSED', [
316
+ 'Quote Not Closed:',
317
+ `the parsing is finished with an opening quote at line ${this.info.lines}`,
318
+ ], this.options, this.__infoField())
319
+ );
320
+ if(err !== undefined) return err;
321
+ }else{
322
+ // Skip last line if it has no characters
323
+ if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){
324
+ this.info.bytes = this.state.bufBytesStart + pos;
325
+ const errField = this.__onField();
326
+ if(errField !== undefined) return errField;
327
+ const errRecord = this.__onRecord(push);
328
+ if(errRecord !== undefined) return errRecord;
329
+ }else if(this.state.wasRowDelimiter === true){
330
+ this.info.empty_lines++;
331
+ }else if(this.state.commenting === true){
332
+ this.info.comment_lines++;
333
+ }
334
+ }
335
+ }else{
336
+ this.state.bufBytesStart += pos;
337
+ this.state.previousBuf = buf.slice(pos);
338
+ }
339
+ if(this.state.wasRowDelimiter === true){
340
+ this.info.lines++;
341
+ this.state.wasRowDelimiter = false;
342
+ }
343
+ },
344
+ __onRecord: function(push){
345
+ const {columns, group_columns_by_name, encoding, info, from, relax_column_count, relax_column_count_less, relax_column_count_more, raw, skip_records_with_empty_values} = this.options;
346
+ const {enabled, record} = this.state;
347
+ if(enabled === false){
348
+ return this.__resetRecord();
349
+ }
350
+ // Convert the first line into column names
351
+ const recordLength = record.length;
352
+ if(columns === true){
353
+ if(skip_records_with_empty_values === true && isRecordEmpty(record)){
354
+ this.__resetRecord();
355
+ return;
356
+ }
357
+ return this.__firstLineToColumns(record);
358
+ }
359
+ if(columns === false && this.info.records === 0){
360
+ this.state.expectedRecordLength = recordLength;
361
+ }
362
+ if(recordLength !== this.state.expectedRecordLength){
363
+ const err = columns === false ?
364
+ new CsvError('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [
365
+ 'Invalid Record Length:',
366
+ `expect ${this.state.expectedRecordLength},`,
367
+ `got ${recordLength} on line ${this.info.lines}`,
368
+ ], this.options, this.__infoField(), {
369
+ record: record,
370
+ })
371
+ :
372
+ new CsvError('CSV_RECORD_INCONSISTENT_COLUMNS', [
373
+ 'Invalid Record Length:',
374
+ `columns length is ${columns.length},`, // rename columns
375
+ `got ${recordLength} on line ${this.info.lines}`,
376
+ ], this.options, this.__infoField(), {
377
+ record: record,
378
+ });
379
+ if(relax_column_count === true ||
380
+ (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) ||
381
+ (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){
382
+ this.info.invalid_field_length++;
383
+ this.state.error = err;
384
+ // Error is undefined with skip_records_with_error
385
+ }else{
386
+ const finalErr = this.__error(err);
387
+ if(finalErr) return finalErr;
388
+ }
389
+ }
390
+ if(skip_records_with_empty_values === true && isRecordEmpty(record)){
391
+ this.__resetRecord();
392
+ return;
393
+ }
394
+ if(this.state.recordHasError === true){
395
+ this.__resetRecord();
396
+ this.state.recordHasError = false;
397
+ return;
398
+ }
399
+ this.info.records++;
400
+ if(from === 1 || this.info.records >= from){
401
+ const {objname} = this.options;
402
+ // With columns, records are object
403
+ if(columns !== false){
404
+ const obj = {};
405
+ // Transform record array to an object
406
+ for(let i = 0, l = record.length; i < l; i++){
407
+ if(columns[i] === undefined || columns[i].disabled) continue;
408
+ // Turn duplicate columns into an array
409
+ if (group_columns_by_name === true && obj[columns[i].name] !== undefined) {
410
+ if (Array.isArray(obj[columns[i].name])) {
411
+ obj[columns[i].name] = obj[columns[i].name].concat(record[i]);
412
+ } else {
413
+ obj[columns[i].name] = [obj[columns[i].name], record[i]];
414
+ }
415
+ } else {
416
+ obj[columns[i].name] = record[i];
417
+ }
418
+ }
419
+ // Without objname (default)
420
+ if(raw === true || info === true){
421
+ const extRecord = Object.assign(
422
+ {record: obj},
423
+ (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}),
424
+ (info === true ? {info: this.__infoRecord()}: {})
425
+ );
426
+ const err = this.__push(
427
+ objname === undefined ? extRecord : [obj[objname], extRecord]
428
+ , push);
429
+ if(err){
430
+ return err;
431
+ }
432
+ }else{
433
+ const err = this.__push(
434
+ objname === undefined ? obj : [obj[objname], obj]
435
+ , push);
436
+ if(err){
437
+ return err;
438
+ }
439
+ }
440
+ // Without columns, records are array
441
+ }else{
442
+ if(raw === true || info === true){
443
+ const extRecord = Object.assign(
444
+ {record: record},
445
+ raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {},
446
+ info === true ? {info: this.__infoRecord()}: {}
447
+ );
448
+ const err = this.__push(
449
+ objname === undefined ? extRecord : [record[objname], extRecord]
450
+ , push);
451
+ if(err){
452
+ return err;
453
+ }
454
+ }else{
455
+ const err = this.__push(
456
+ objname === undefined ? record : [record[objname], record]
457
+ , push);
458
+ if(err){
459
+ return err;
460
+ }
461
+ }
462
+ }
463
+ }
464
+ this.__resetRecord();
465
+ },
466
+ __firstLineToColumns: function(record){
467
+ const {firstLineToHeaders} = this.state;
468
+ try{
469
+ const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record);
470
+ if(!Array.isArray(headers)){
471
+ return this.__error(
472
+ new CsvError('CSV_INVALID_COLUMN_MAPPING', [
473
+ 'Invalid Column Mapping:',
474
+ 'expect an array from column function,',
475
+ `got ${JSON.stringify(headers)}`
476
+ ], this.options, this.__infoField(), {
477
+ headers: headers,
478
+ })
479
+ );
480
+ }
481
+ const normalizedHeaders = normalize_columns_array(headers);
482
+ this.state.expectedRecordLength = normalizedHeaders.length;
483
+ this.options.columns = normalizedHeaders;
484
+ this.__resetRecord();
485
+ return;
486
+ }catch(err){
487
+ return err;
488
+ }
489
+ },
490
+ __resetRecord: function(){
491
+ if(this.options.raw === true){
492
+ this.state.rawBuffer.reset();
493
+ }
494
+ this.state.error = undefined;
495
+ this.state.record = [];
496
+ this.state.record_length = 0;
497
+ },
498
+ __onField: function(){
499
+ const {cast, encoding, rtrim, max_record_size} = this.options;
500
+ const {enabled, wasQuoting} = this.state;
501
+ // Short circuit for the from_line options
502
+ if(enabled === false){
503
+ return this.__resetField();
504
+ }
505
+ let field = this.state.field.toString(encoding);
506
+ if(rtrim === true && wasQuoting === false){
507
+ field = field.trimRight();
508
+ }
509
+ if(cast === true){
510
+ const [err, f] = this.__cast(field);
511
+ if(err !== undefined) return err;
512
+ field = f;
513
+ }
514
+ this.state.record.push(field);
515
+ // Increment record length if record size must not exceed a limit
516
+ if(max_record_size !== 0 && typeof field === 'string'){
517
+ this.state.record_length += field.length;
518
+ }
519
+ this.__resetField();
520
+ },
521
+ __resetField: function(){
522
+ this.state.field.reset();
523
+ this.state.wasQuoting = false;
524
+ },
525
+ __push: function(record, push){
526
+ const {on_record} = this.options;
527
+ if(on_record !== undefined){
528
+ const info = this.__infoRecord();
529
+ try{
530
+ record = on_record.call(null, record, info);
531
+ }catch(err){
532
+ return err;
533
+ }
534
+ if(record === undefined || record === null){ return; }
535
+ }
536
+ push(record);
537
+ },
538
+ // Return a tuple with the error and the casted value
539
+ __cast: function(field){
540
+ const {columns, relax_column_count} = this.options;
541
+ const isColumns = Array.isArray(columns);
542
+ // Dont loose time calling cast
543
+ // because the final record is an object
544
+ // and this field can't be associated to a key present in columns
545
+ if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){
546
+ return [undefined, undefined];
547
+ }
548
+ if(this.state.castField !== null){
549
+ try{
550
+ const info = this.__infoField();
551
+ return [undefined, this.state.castField.call(null, field, info)];
552
+ }catch(err){
553
+ return [err];
554
+ }
555
+ }
556
+ if(this.__isFloat(field)){
557
+ return [undefined, parseFloat(field)];
558
+ }else if(this.options.cast_date !== false){
559
+ const info = this.__infoField();
560
+ return [undefined, this.options.cast_date.call(null, field, info)];
561
+ }
562
+ return [undefined, field];
563
+ },
564
+ // Helper to test if a character is a space or a line delimiter
565
+ __isCharTrimable: function(buf, pos){
566
+ const isTrim = (buf, pos) => {
567
+ const {timchars} = this.state;
568
+ loop1: for(let i = 0; i < timchars.length; i++){
569
+ const timchar = timchars[i];
570
+ for(let j = 0; j < timchar.length; j++){
571
+ if(timchar[j] !== buf[pos+j]) continue loop1;
572
+ }
573
+ return timchar.length;
574
+ }
575
+ return 0;
576
+ };
577
+ return isTrim(buf, pos);
578
+ },
579
+ // Keep it in case we implement the `cast_int` option
580
+ // __isInt(value){
581
+ // // return Number.isInteger(parseInt(value))
582
+ // // return !isNaN( parseInt( obj ) );
583
+ // return /^(\-|\+)?[1-9][0-9]*$/.test(value)
584
+ // }
585
+ __isFloat: function(value){
586
+ return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery
587
+ },
588
+ __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){
589
+ if(sourceBuf[0] !== firstByte) return 0;
590
+ const sourceLength = sourceBuf.length;
591
+ for(let i = 1; i < sourceLength; i++){
592
+ if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0;
593
+ }
594
+ return sourceLength;
595
+ },
596
+ __isDelimiter: function(buf, pos, chr){
597
+ const {delimiter, ignore_last_delimiters} = this.options;
598
+ if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){
599
+ return 0;
600
+ }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){
601
+ return 0;
602
+ }
603
+ loop1: for(let i = 0; i < delimiter.length; i++){
604
+ const del = delimiter[i];
605
+ if(del[0] === chr){
606
+ for(let j = 1; j < del.length; j++){
607
+ if(del[j] !== buf[pos+j]) continue loop1;
608
+ }
609
+ return del.length;
610
+ }
611
+ }
612
+ return 0;
613
+ },
614
+ __isRecordDelimiter: function(chr, buf, pos){
615
+ const {record_delimiter} = this.options;
616
+ const recordDelimiterLength = record_delimiter.length;
617
+ loop1: for(let i = 0; i < recordDelimiterLength; i++){
618
+ const rd = record_delimiter[i];
619
+ const rdLength = rd.length;
620
+ if(rd[0] !== chr){
621
+ continue;
622
+ }
623
+ for(let j = 1; j < rdLength; j++){
624
+ if(rd[j] !== buf[pos+j]){
625
+ continue loop1;
626
+ }
627
+ }
628
+ return rd.length;
629
+ }
630
+ return 0;
631
+ },
632
+ __isEscape: function(buf, pos, chr){
633
+ const {escape} = this.options;
634
+ if(escape === null) return false;
635
+ const l = escape.length;
636
+ if(escape[0] === chr){
637
+ for(let i = 0; i < l; i++){
638
+ if(escape[i] !== buf[pos+i]){
639
+ return false;
640
+ }
641
+ }
642
+ return true;
643
+ }
644
+ return false;
645
+ },
646
+ __isQuote: function(buf, pos){
647
+ const {quote} = this.options;
648
+ if(quote === null) return false;
649
+ const l = quote.length;
650
+ for(let i = 0; i < l; i++){
651
+ if(quote[i] !== buf[pos+i]){
652
+ return false;
653
+ }
654
+ }
655
+ return true;
656
+ },
657
+ __autoDiscoverRecordDelimiter: function(buf, pos){
658
+ const { encoding } = this.options;
659
+ // Note, we don't need to cache this information in state,
660
+ // It is only called on the first line until we find out a suitable
661
+ // record delimiter.
662
+ const rds = [
663
+ // Important, the windows line ending must be before mac os 9
664
+ Buffer.from('\r\n', encoding),
665
+ Buffer.from('\n', encoding),
666
+ Buffer.from('\r', encoding),
667
+ ];
668
+ loop: for(let i = 0; i < rds.length; i++){
669
+ const l = rds[i].length;
670
+ for(let j = 0; j < l; j++){
671
+ if(rds[i][j] !== buf[pos + j]){
672
+ continue loop;
673
+ }
674
+ }
675
+ this.options.record_delimiter.push(rds[i]);
676
+ this.state.recordDelimiterMaxLength = rds[i].length;
677
+ return rds[i].length;
678
+ }
679
+ return 0;
680
+ },
681
+ __error: function(msg){
682
+ const {encoding, raw, skip_records_with_error} = this.options;
683
+ const err = typeof msg === 'string' ? new Error(msg) : msg;
684
+ if(skip_records_with_error){
685
+ this.state.recordHasError = true;
686
+ if(this.options.on_skip !== undefined){
687
+ this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined);
688
+ }
689
+ // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined);
690
+ return undefined;
691
+ }else{
692
+ return err;
693
+ }
694
+ },
695
+ __infoDataSet: function(){
696
+ return {
697
+ ...this.info,
698
+ columns: this.options.columns
699
+ };
700
+ },
701
+ __infoRecord: function(){
702
+ const {columns, raw, encoding} = this.options;
703
+ return {
704
+ ...this.__infoDataSet(),
705
+ error: this.state.error,
706
+ header: columns === true,
707
+ index: this.state.record.length,
708
+ raw: raw ? this.state.rawBuffer.toString(encoding) : undefined
709
+ };
710
+ },
711
+ __infoField: function(){
712
+ const {columns} = this.options;
713
+ const isColumns = Array.isArray(columns);
714
+ return {
715
+ ...this.__infoRecord(),
716
+ column: isColumns === true ?
717
+ (columns.length > this.state.record.length ?
718
+ columns[this.state.record.length].name :
719
+ null
720
+ ) :
721
+ this.state.record.length,
722
+ quoting: this.state.wasQuoting,
723
+ };
724
+ }
725
+ };
726
+ };
727
+
728
+
729
+ export {transform, CsvError};