diff --git a/package.json b/package.json index b50108670..835aa871a 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "build": "lerna run build", "postinstall": "husky install", "publish": "lerna publish from-git --yes", - "lint": "lerna run lint", + "lint:check": "lerna run lint:check", + "lint:fix": "lerna run lint:fix", "pretest": "npm run lint", "test": "lerna run test", "test:legacy": "lerna run test:legacy", diff --git a/packages/csv-generate/.eslintrc.yml b/packages/csv-generate/.eslintrc.yml deleted file mode 100644 index 4581986eb..000000000 --- a/packages/csv-generate/.eslintrc.yml +++ /dev/null @@ -1,21 +0,0 @@ -env: - commonjs: true - es6: true - node: true -extends: "eslint:recommended" -globals: - Atomics: "readonly" - SharedArrayBuffer: "readonly" -parserOptions: - ecmaVersion: "latest" - sourceType: "module" -rules: - no-var: "error" - semi: "error" - indent: ["error", 2] - linebreak-style: ["error", "unix"] - no-multi-spaces: "error" - space-in-parens: "error" - no-multiple-empty-lines: "error" - prefer-const: "error" - no-use-before-define: "error" diff --git a/packages/csv-generate/.travis.yml b/packages/csv-generate/.travis.yml deleted file mode 100644 index 68e5391ac..000000000 --- a/packages/csv-generate/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - "10" - - "11" - - "12" diff --git a/packages/csv-generate/coffeelint.json b/packages/csv-generate/coffeelint.json deleted file mode 100644 index db57f258d..000000000 --- a/packages/csv-generate/coffeelint.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "arrow_spacing": { - "level": "ignore" - }, - "braces_spacing": { - "level": "ignore", - "spaces": 0, - "empty_object_spaces": 0 - }, - "camel_case_classes": { - "level": "error" - }, - "coffeescript_error": { - "level": "error" - }, - "colon_assignment_spacing": { - "level": "ignore", - "spacing": { - "left": 0, - "right": 0 - } - }, - "cyclomatic_complexity": { - "level": "ignore", - "value": 10 - }, - "duplicate_key": { - "level": "error" - }, - "empty_constructor_needs_parens": { - "level": "ignore" - }, - "ensure_comprehensions": { - "level": "warn" - }, - "eol_last": { - "level": "ignore" - }, - "indentation": { - "value": 2, - "level": "error" - }, - "line_endings": { - "level": "error", - "value": "unix" - }, - "max_line_length": { - "value": 80, - "level": "ignore", - "limitComments": true - }, - "missing_fat_arrows": { - "level": "ignore", - "is_strict": false - }, - "newlines_after_classes": { - "value": 3, - "level": "ignore" - }, - "no_backticks": { - "level": "error" - }, - "no_debugger": { - "level": "warn", - "console": false - }, - "no_empty_functions": { - "level": "ignore" - }, - "no_empty_param_list": { - "level": "ignore" - }, - "no_implicit_braces": { - "level": "ignore", - "strict": true - }, - "no_implicit_parens": { - "level": "ignore", - "strict": true - }, - "no_interpolation_in_single_quotes": { - "level": "ignore" - }, - "no_nested_string_interpolation": { - "level": "warn" - }, - "no_plusplus": { - "level": "ignore" - }, - "no_private_function_fat_arrows": { - "level": "warn" - }, - "no_stand_alone_at": { - "level": "ignore" - }, - "no_tabs": { - "level": "error" - }, - "no_this": { - "level": "ignore" - }, - "no_throwing_strings": { - "level": "error" - }, - "no_trailing_semicolons": { - "level": "error" - }, - "no_trailing_whitespace": { - "level": "error", - "allowed_in_comments": false, - "allowed_in_empty_lines": true - }, - "no_unnecessary_double_quotes": { - "level": "ignore" - }, - "no_unnecessary_fat_arrows": { - "level": "warn" - }, - "non_empty_constructor_needs_parens": { - "level": "ignore" - }, - "prefer_english_operator": { - "level": "ignore", - "doubleNotLevel": "ignore" - }, - "space_operators": { - "level": "ignore" - }, - "spacing_after_comma": { - "level": "ignore" - }, - "transform_messes_up_line_numbers": { - "level": "warn" - } -} diff --git a/packages/csv-generate/dist/cjs/index.cjs b/packages/csv-generate/dist/cjs/index.cjs index 4187f6a06..8bfd4ed05 100644 --- a/packages/csv-generate/dist/cjs/index.cjs +++ b/packages/csv-generate/dist/cjs/index.cjs @@ -7,54 +7,54 @@ const init_state = (options) => { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. -const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { +const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -63,13 +63,13 @@ const normalize_options = (opts) => { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -77,28 +77,32 @@ const normalize_options = (opts) => { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -113,7 +117,7 @@ const read = (options, state, size, push, close) => { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -143,48 +147,54 @@ const read = (options, state, size, push, close) => { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -193,7 +203,15 @@ const read = (options, state, size, push, close) => { } }; -const Generator = function(options = {}){ +/* +CSV Generate - main module + +Please look at the [project documentation](https://csv.js.org/generate/) for +additional information. +*/ + + +const Generator = function (options = {}) { this.options = normalize_options(options); // Call parent constructor stream.Readable.call(this, this.options); @@ -203,70 +221,77 @@ const Generator = function(options = {}){ util.inherits(Generator, stream.Readable); // Stop the generation. -Generator.prototype.end = function(){ +Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. -Generator.prototype._read = function(size){ +Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; -Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); +Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. -Generator.prototype.__push = function(record){ +Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; -const generate = function(){ +const generate = function () { let options; let callback; - if(arguments.length === 2){ + if (arguments.length === 2) { options = arguments[0]; callback = arguments[1]; - }else if(arguments.length === 1){ - if(typeof arguments[0] === 'function'){ + } else if (arguments.length === 1) { + if (typeof arguments[0] === "function") { options = {}; callback = arguments[0]; - }else { + } else { options = arguments[0]; } - }else if(arguments.length === 0){ + } else if (arguments.length === 0) { options = {}; } const generator = new Generator(options); - if(callback){ + if (callback) { const data = []; - generator.on('readable', function(){ - let d; while((d = generator.read()) !== null){ + generator.on("readable", function () { + let d; + while ((d = generator.read()) !== null) { data.push(d); } }); - generator.on('error', callback); - generator.on('end', function(){ - if(generator.options.objectMode){ + generator.on("error", callback); + generator.on("end", function () { + if (generator.options.objectMode) { callback(null, data); - }else { - if(generator.options.encoding){ - callback(null, data.join('')); - }else { + } else { + if (generator.options.encoding) { + callback(null, data.join("")); + } else { callback(null, Buffer.concat(data)); } } diff --git a/packages/csv-generate/dist/cjs/sync.cjs b/packages/csv-generate/dist/cjs/sync.cjs index a43003d0c..051739202 100644 --- a/packages/csv-generate/dist/cjs/sync.cjs +++ b/packages/csv-generate/dist/cjs/sync.cjs @@ -7,54 +7,54 @@ const init_state = (options) => { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. -const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { +const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -63,13 +63,13 @@ const normalize_options = (opts) => { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -77,28 +77,32 @@ const normalize_options = (opts) => { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -113,7 +117,7 @@ const read = (options, state, size, push, close) => { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -143,48 +147,54 @@ const read = (options, state, size, push, close) => { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -193,7 +203,15 @@ const read = (options, state, size, push, close) => { } }; -const Generator = function(options = {}){ +/* +CSV Generate - main module + +Please look at the [project documentation](https://csv.js.org/generate/) for +additional information. +*/ + + +const Generator = function (options = {}) { this.options = normalize_options(options); // Call parent constructor stream.Readable.call(this, this.options); @@ -203,65 +221,79 @@ const Generator = function(options = {}){ util.inherits(Generator, stream.Readable); // Stop the generation. -Generator.prototype.end = function(){ +Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. -Generator.prototype._read = function(size){ +Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; -Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); +Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. -Generator.prototype.__push = function(record){ +Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; -const generate = function(options){ - if(typeof options === 'string' && /\d+/.test(options)){ +/* +CSV Generate - sync module + +Please look at the [project documentation](https://csv.js.org/generate/) for +additional information. +*/ + + +const generate = function (options) { + if (typeof options === "string" && /\d+/.test(options)) { options = parseInt(options); } - if(Number.isInteger(options)){ - options = {length: options}; - }else if(typeof options !== 'object' || options === null){ - throw Error('Invalid Argument: options must be an object or an integer'); + if (Number.isInteger(options)) { + options = { length: options }; + } else if (typeof options !== "object" || options === null) { + throw Error("Invalid Argument: options must be an object or an integer"); } - if(!Number.isInteger(options.length)){ - throw Error('Invalid Argument: length is not defined'); + if (!Number.isInteger(options.length)) { + throw Error("Invalid Argument: length is not defined"); } const chunks = []; let work = true; const generator = new Generator(options); - generator.push = function(chunk){ - if(chunk === null){ - return work = false; + generator.push = function (chunk) { + if (chunk === null) { + return (work = false); } - chunks.push(chunk); + chunks.push(chunk); }; - while(work){ + while (work) { generator.__read(options.highWaterMark); } - if(!options.objectMode){ - return chunks.join(''); - }else { + if (!options.objectMode) { + return chunks.join(""); + } else { return chunks; } }; diff --git a/packages/csv-generate/dist/esm/index.js b/packages/csv-generate/dist/esm/index.js index 68bfeb88e..79c042d6a 100644 --- a/packages/csv-generate/dist/esm/index.js +++ b/packages/csv-generate/dist/esm/index.js @@ -2000,7 +2000,7 @@ EventEmitter.init = function() { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5198,54 +5198,54 @@ const init_state = (options) => { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. -const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { +const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5254,13 +5254,13 @@ const normalize_options = (opts) => { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5268,28 +5268,32 @@ const normalize_options = (opts) => { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5304,7 +5308,7 @@ const read = (options, state, size, push, close) => { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5334,48 +5338,54 @@ const read = (options, state, size, push, close) => { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5384,7 +5394,7 @@ const read = (options, state, size, push, close) => { } }; -const Generator = function(options = {}){ +const Generator = function (options = {}) { this.options = normalize_options(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5394,70 +5404,77 @@ const Generator = function(options = {}){ util.inherits(Generator, Stream.Readable); // Stop the generation. -Generator.prototype.end = function(){ +Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. -Generator.prototype._read = function(size){ +Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; -Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); +Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. -Generator.prototype.__push = function(record){ +Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; -const generate = function(){ +const generate = function () { let options; let callback; - if(arguments.length === 2){ + if (arguments.length === 2) { options = arguments[0]; callback = arguments[1]; - }else if(arguments.length === 1){ - if(typeof arguments[0] === 'function'){ + } else if (arguments.length === 1) { + if (typeof arguments[0] === "function") { options = {}; callback = arguments[0]; - }else { + } else { options = arguments[0]; } - }else if(arguments.length === 0){ + } else if (arguments.length === 0) { options = {}; } const generator = new Generator(options); - if(callback){ + if (callback) { const data = []; - generator.on('readable', function(){ - let d; while((d = generator.read()) !== null){ + generator.on("readable", function () { + let d; + while ((d = generator.read()) !== null) { data.push(d); } }); - generator.on('error', callback); - generator.on('end', function(){ - if(generator.options.objectMode){ + generator.on("error", callback); + generator.on("end", function () { + if (generator.options.objectMode) { callback(null, data); - }else { - if(generator.options.encoding){ - callback(null, data.join('')); - }else { + } else { + if (generator.options.encoding) { + callback(null, data.join("")); + } else { callback(null, Buffer.concat(data)); } } diff --git a/packages/csv-generate/dist/esm/sync.js b/packages/csv-generate/dist/esm/sync.js index a2853f70d..6c0f32d1c 100644 --- a/packages/csv-generate/dist/esm/sync.js +++ b/packages/csv-generate/dist/esm/sync.js @@ -2000,7 +2000,7 @@ EventEmitter.init = function() { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5198,54 +5198,54 @@ const init_state = (options) => { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. -const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { +const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5254,13 +5254,13 @@ const normalize_options = (opts) => { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5268,28 +5268,32 @@ const normalize_options = (opts) => { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5304,7 +5308,7 @@ const read = (options, state, size, push, close) => { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5334,48 +5338,54 @@ const read = (options, state, size, push, close) => { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5384,7 +5394,7 @@ const read = (options, state, size, push, close) => { } }; -const Generator = function(options = {}){ +const Generator = function (options = {}) { this.options = normalize_options(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5394,65 +5404,79 @@ const Generator = function(options = {}){ util.inherits(Generator, Stream.Readable); // Stop the generation. -Generator.prototype.end = function(){ +Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. -Generator.prototype._read = function(size){ +Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; -Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); +Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. -Generator.prototype.__push = function(record){ +Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; -const generate = function(options){ - if(typeof options === 'string' && /\d+/.test(options)){ +/* +CSV Generate - sync module + +Please look at the [project documentation](https://csv.js.org/generate/) for +additional information. +*/ + + +const generate = function (options) { + if (typeof options === "string" && /\d+/.test(options)) { options = parseInt(options); } - if(Number.isInteger(options)){ - options = {length: options}; - }else if(typeof options !== 'object' || options === null){ - throw Error('Invalid Argument: options must be an object or an integer'); + if (Number.isInteger(options)) { + options = { length: options }; + } else if (typeof options !== "object" || options === null) { + throw Error("Invalid Argument: options must be an object or an integer"); } - if(!Number.isInteger(options.length)){ - throw Error('Invalid Argument: length is not defined'); + if (!Number.isInteger(options.length)) { + throw Error("Invalid Argument: length is not defined"); } const chunks = []; let work = true; const generator = new Generator(options); - generator.push = function(chunk){ - if(chunk === null){ - return work = false; + generator.push = function (chunk) { + if (chunk === null) { + return (work = false); } - chunks.push(chunk); + chunks.push(chunk); }; - while(work){ + while (work) { generator.__read(options.highWaterMark); } - if(!options.objectMode){ - return chunks.join(''); - }else { + if (!options.objectMode) { + return chunks.join(""); + } else { return chunks; } }; diff --git a/packages/csv-generate/dist/iife/index.js b/packages/csv-generate/dist/iife/index.js index 22278f312..2301b7b21 100644 --- a/packages/csv-generate/dist/iife/index.js +++ b/packages/csv-generate/dist/iife/index.js @@ -2003,7 +2003,7 @@ var csv_generate = (function (exports) { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5201,54 +5201,54 @@ var csv_generate = (function (exports) { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. - const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { + const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5257,13 +5257,13 @@ var csv_generate = (function (exports) { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5271,28 +5271,32 @@ var csv_generate = (function (exports) { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5307,7 +5311,7 @@ var csv_generate = (function (exports) { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5337,48 +5341,54 @@ var csv_generate = (function (exports) { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5387,7 +5397,7 @@ var csv_generate = (function (exports) { } }; - const Generator = function(options = {}){ + const Generator = function (options = {}) { this.options = normalize_options(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5397,70 +5407,77 @@ var csv_generate = (function (exports) { util.inherits(Generator, Stream.Readable); // Stop the generation. - Generator.prototype.end = function(){ + Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. - Generator.prototype._read = function(size){ + Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; - Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); + Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. - Generator.prototype.__push = function(record){ + Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; - const generate = function(){ + const generate = function () { let options; let callback; - if(arguments.length === 2){ + if (arguments.length === 2) { options = arguments[0]; callback = arguments[1]; - }else if(arguments.length === 1){ - if(typeof arguments[0] === 'function'){ + } else if (arguments.length === 1) { + if (typeof arguments[0] === "function") { options = {}; callback = arguments[0]; - }else { + } else { options = arguments[0]; } - }else if(arguments.length === 0){ + } else if (arguments.length === 0) { options = {}; } const generator = new Generator(options); - if(callback){ + if (callback) { const data = []; - generator.on('readable', function(){ - let d; while((d = generator.read()) !== null){ + generator.on("readable", function () { + let d; + while ((d = generator.read()) !== null) { data.push(d); } }); - generator.on('error', callback); - generator.on('end', function(){ - if(generator.options.objectMode){ + generator.on("error", callback); + generator.on("end", function () { + if (generator.options.objectMode) { callback(null, data); - }else { - if(generator.options.encoding){ - callback(null, data.join('')); - }else { + } else { + if (generator.options.encoding) { + callback(null, data.join("")); + } else { callback(null, Buffer.concat(data)); } } diff --git a/packages/csv-generate/dist/iife/sync.js b/packages/csv-generate/dist/iife/sync.js index aaf06edcb..9b1463a18 100644 --- a/packages/csv-generate/dist/iife/sync.js +++ b/packages/csv-generate/dist/iife/sync.js @@ -2003,7 +2003,7 @@ var csv_generate_sync = (function (exports) { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5201,54 +5201,54 @@ var csv_generate_sync = (function (exports) { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. - const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { + const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5257,13 +5257,13 @@ var csv_generate_sync = (function (exports) { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5271,28 +5271,32 @@ var csv_generate_sync = (function (exports) { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5307,7 +5311,7 @@ var csv_generate_sync = (function (exports) { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5337,48 +5341,54 @@ var csv_generate_sync = (function (exports) { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5387,7 +5397,7 @@ var csv_generate_sync = (function (exports) { } }; - const Generator = function(options = {}){ + const Generator = function (options = {}) { this.options = normalize_options(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5397,65 +5407,79 @@ var csv_generate_sync = (function (exports) { util.inherits(Generator, Stream.Readable); // Stop the generation. - Generator.prototype.end = function(){ + Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. - Generator.prototype._read = function(size){ + Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; - Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); + Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. - Generator.prototype.__push = function(record){ + Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; - const generate = function(options){ - if(typeof options === 'string' && /\d+/.test(options)){ + /* + CSV Generate - sync module + + Please look at the [project documentation](https://csv.js.org/generate/) for + additional information. + */ + + + const generate = function (options) { + if (typeof options === "string" && /\d+/.test(options)) { options = parseInt(options); } - if(Number.isInteger(options)){ - options = {length: options}; - }else if(typeof options !== 'object' || options === null){ - throw Error('Invalid Argument: options must be an object or an integer'); + if (Number.isInteger(options)) { + options = { length: options }; + } else if (typeof options !== "object" || options === null) { + throw Error("Invalid Argument: options must be an object or an integer"); } - if(!Number.isInteger(options.length)){ - throw Error('Invalid Argument: length is not defined'); + if (!Number.isInteger(options.length)) { + throw Error("Invalid Argument: length is not defined"); } const chunks = []; let work = true; const generator = new Generator(options); - generator.push = function(chunk){ - if(chunk === null){ - return work = false; + generator.push = function (chunk) { + if (chunk === null) { + return (work = false); } - chunks.push(chunk); + chunks.push(chunk); }; - while(work){ + while (work) { generator.__read(options.highWaterMark); } - if(!options.objectMode){ - return chunks.join(''); - }else { + if (!options.objectMode) { + return chunks.join(""); + } else { return chunks; } }; diff --git a/packages/csv-generate/dist/umd/index.js b/packages/csv-generate/dist/umd/index.js index 0c66ce6e7..09d7900b5 100644 --- a/packages/csv-generate/dist/umd/index.js +++ b/packages/csv-generate/dist/umd/index.js @@ -2006,7 +2006,7 @@ this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5204,54 +5204,54 @@ // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. - const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { + const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5260,13 +5260,13 @@ // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5274,28 +5274,32 @@ fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5310,7 +5314,7 @@ // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5340,48 +5344,54 @@ // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5390,7 +5400,7 @@ } }; - const Generator = function(options = {}){ + const Generator = function (options = {}) { this.options = normalize_options(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5400,70 +5410,77 @@ util.inherits(Generator, Stream.Readable); // Stop the generation. - Generator.prototype.end = function(){ + Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. - Generator.prototype._read = function(size){ + Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; - Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); + Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. - Generator.prototype.__push = function(record){ + Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; - const generate = function(){ + const generate = function () { let options; let callback; - if(arguments.length === 2){ + if (arguments.length === 2) { options = arguments[0]; callback = arguments[1]; - }else if(arguments.length === 1){ - if(typeof arguments[0] === 'function'){ + } else if (arguments.length === 1) { + if (typeof arguments[0] === "function") { options = {}; callback = arguments[0]; - }else { + } else { options = arguments[0]; } - }else if(arguments.length === 0){ + } else if (arguments.length === 0) { options = {}; } const generator = new Generator(options); - if(callback){ + if (callback) { const data = []; - generator.on('readable', function(){ - let d; while((d = generator.read()) !== null){ + generator.on("readable", function () { + let d; + while ((d = generator.read()) !== null) { data.push(d); } }); - generator.on('error', callback); - generator.on('end', function(){ - if(generator.options.objectMode){ + generator.on("error", callback); + generator.on("end", function () { + if (generator.options.objectMode) { callback(null, data); - }else { - if(generator.options.encoding){ - callback(null, data.join('')); - }else { + } else { + if (generator.options.encoding) { + callback(null, data.join("")); + } else { callback(null, Buffer.concat(data)); } } diff --git a/packages/csv-generate/dist/umd/sync.js b/packages/csv-generate/dist/umd/sync.js index c5a4a47fd..e1d938dd5 100644 --- a/packages/csv-generate/dist/umd/sync.js +++ b/packages/csv-generate/dist/umd/sync.js @@ -2006,7 +2006,7 @@ this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5204,54 +5204,54 @@ // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. - const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { + const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5260,13 +5260,13 @@ // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5274,28 +5274,32 @@ fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5310,7 +5314,7 @@ // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5340,48 +5344,54 @@ // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5390,7 +5400,7 @@ } }; - const Generator = function(options = {}){ + const Generator = function (options = {}) { this.options = normalize_options(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5400,65 +5410,79 @@ util.inherits(Generator, Stream.Readable); // Stop the generation. - Generator.prototype.end = function(){ + Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. - Generator.prototype._read = function(size){ + Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; - Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); + Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. - Generator.prototype.__push = function(record){ + Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; - const generate = function(options){ - if(typeof options === 'string' && /\d+/.test(options)){ + /* + CSV Generate - sync module + + Please look at the [project documentation](https://csv.js.org/generate/) for + additional information. + */ + + + const generate = function (options) { + if (typeof options === "string" && /\d+/.test(options)) { options = parseInt(options); } - if(Number.isInteger(options)){ - options = {length: options}; - }else if(typeof options !== 'object' || options === null){ - throw Error('Invalid Argument: options must be an object or an integer'); + if (Number.isInteger(options)) { + options = { length: options }; + } else if (typeof options !== "object" || options === null) { + throw Error("Invalid Argument: options must be an object or an integer"); } - if(!Number.isInteger(options.length)){ - throw Error('Invalid Argument: length is not defined'); + if (!Number.isInteger(options.length)) { + throw Error("Invalid Argument: length is not defined"); } const chunks = []; let work = true; const generator = new Generator(options); - generator.push = function(chunk){ - if(chunk === null){ - return work = false; + generator.push = function (chunk) { + if (chunk === null) { + return (work = false); } - chunks.push(chunk); + chunks.push(chunk); }; - while(work){ + while (work) { generator.__read(options.highWaterMark); } - if(!options.objectMode){ - return chunks.join(''); - }else { + if (!options.objectMode) { + return chunks.join(""); + } else { return chunks; } }; diff --git a/packages/csv-generate/eslint.config.js b/packages/csv-generate/eslint.config.js new file mode 100644 index 000000000..c129c277f --- /dev/null +++ b/packages/csv-generate/eslint.config.js @@ -0,0 +1,16 @@ +import globals from "globals"; +import js from "@eslint/js"; +import mocha from "eslint-plugin-mocha"; +import prettier from "eslint-plugin-prettier/recommended"; + +export default [ + { + ignores: ["dist/**"], + }, + { + languageOptions: { globals: { ...globals.node } }, + }, + js.configs.recommended, + mocha.configs.flat.recommended, + prettier, +]; diff --git a/packages/csv-generate/lib/api/index.js b/packages/csv-generate/lib/api/index.js index fdfbddcb7..052868e19 100644 --- a/packages/csv-generate/lib/api/index.js +++ b/packages/csv-generate/lib/api/index.js @@ -1,6 +1,5 @@ +import { init_state } from "./init_state.js"; +import { normalize_options } from "./normalize_options.js"; +import { read } from "./read.js"; -import {init_state} from './init_state.js'; -import {normalize_options} from './normalize_options.js'; -import {read} from './read.js'; - -export {normalize_options, init_state, read}; +export { normalize_options, init_state, read }; diff --git a/packages/csv-generate/lib/api/init_state.js b/packages/csv-generate/lib/api/init_state.js index b99e2695d..aa9ea5e80 100644 --- a/packages/csv-generate/lib/api/init_state.js +++ b/packages/csv-generate/lib/api/init_state.js @@ -1,12 +1,11 @@ - const init_state = (options) => { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; -export {init_state}; +export { init_state }; diff --git a/packages/csv-generate/lib/api/normalize_options.js b/packages/csv-generate/lib/api/normalize_options.js index 80a24930f..ccf6eb169 100644 --- a/packages/csv-generate/lib/api/normalize_options.js +++ b/packages/csv-generate/lib/api/normalize_options.js @@ -1,18 +1,17 @@ +import { types } from "./types.js"; -import {types} from './types.js'; - -const camelize = function(str){ - return str.replace(/_([a-z])/gi, function(_, match){ +const camelize = function (str) { + return str.replace(/_([a-z])/gi, function (_, match) { return match.toUpperCase(); }); }; const normalize_options = (opts) => { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -21,13 +20,13 @@ const normalize_options = (opts) => { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -35,28 +34,32 @@ const normalize_options = (opts) => { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } diff --git a/packages/csv-generate/lib/api/random.js b/packages/csv-generate/lib/api/random.js index 04692e558..f07c409ce 100644 --- a/packages/csv-generate/lib/api/random.js +++ b/packages/csv-generate/lib/api/random.js @@ -1,11 +1,10 @@ - // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. -const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else{ +const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; -export {random}; +export { random }; diff --git a/packages/csv-generate/lib/api/read.js b/packages/csv-generate/lib/api/read.js index a94c3c416..8d7b63b85 100644 --- a/packages/csv-generate/lib/api/read.js +++ b/packages/csv-generate/lib/api/read.js @@ -1,4 +1,3 @@ - const read = (options, state, size, push, close) => { // Already started const data = []; @@ -6,7 +5,7 @@ const read = (options, state, size, push, close) => { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -36,48 +35,54 @@ const read = (options, state, size, push, close) => { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else{ + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else{ - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else{ + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -86,4 +91,4 @@ const read = (options, state, size, push, close) => { } }; -export {read}; +export { read }; diff --git a/packages/csv-generate/lib/api/types.js b/packages/csv-generate/lib/api/types.js index e2e703b11..9400764af 100644 --- a/packages/csv-generate/lib/api/types.js +++ b/packages/csv-generate/lib/api/types.js @@ -1,25 +1,24 @@ - -import {random} from './random.js'; +import { random } from "./random.js"; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { this.__read(size); }); }; -Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else{ - this.push(null); - } - }); +Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. -Generator.prototype.__push = function(record){ +Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; -const generate = function(){ +const generate = function () { let options; let callback; - if(arguments.length === 2){ + if (arguments.length === 2) { options = arguments[0]; callback = arguments[1]; - }else if(arguments.length === 1){ - if(typeof arguments[0] === 'function'){ + } else if (arguments.length === 1) { + if (typeof arguments[0] === "function") { options = {}; callback = arguments[0]; - }else{ + } else { options = arguments[0]; } - }else if(arguments.length === 0){ + } else if (arguments.length === 0) { options = {}; } const generator = new Generator(options); - if(callback){ + if (callback) { const data = []; - generator.on('readable', function(){ - let d; while((d = generator.read()) !== null){ + generator.on("readable", function () { + let d; + while ((d = generator.read()) !== null) { data.push(d); } }); - generator.on('error', callback); - generator.on('end', function(){ - if(generator.options.objectMode){ + generator.on("error", callback); + generator.on("end", function () { + if (generator.options.objectMode) { callback(null, data); - }else{ - if(generator.options.encoding){ - callback(null, data.join('')); - }else{ + } else { + if (generator.options.encoding) { + callback(null, data.join("")); + } else { callback(null, Buffer.concat(data)); } } @@ -93,4 +99,4 @@ const generate = function(){ }; // export default generate -export {generate, Generator}; +export { generate, Generator }; diff --git a/packages/csv-generate/lib/stream.js b/packages/csv-generate/lib/stream.js index 38ca13946..88c88f2f8 100644 --- a/packages/csv-generate/lib/stream.js +++ b/packages/csv-generate/lib/stream.js @@ -1,23 +1,29 @@ - -import { - ReadableStream, -} from 'node:stream/web'; -import {normalize_options, init_state, read} from './api/index.js'; +import { ReadableStream } from "node:stream/web"; +import { normalize_options, init_state, read } from "./api/index.js"; const generate = (opts) => { const options = normalize_options(opts || {}); const state = init_state(options); - return new ReadableStream({ - async pull(controller) { - read(options, state, 1024, function(chunk) { - chunk = Buffer.from(chunk); - controller.enqueue(chunk); - }, function(){ - controller.close(); - }); - } - }, {highWaterMark: 1024}); + return new ReadableStream( + { + async pull(controller) { + read( + options, + state, + 1024, + function (chunk) { + chunk = Buffer.from(chunk); + controller.enqueue(chunk); + }, + function () { + controller.close(); + }, + ); + }, + }, + { highWaterMark: 1024 }, + ); // return new Generator(options || {}) }; -export {generate}; +export { generate }; diff --git a/packages/csv-generate/lib/sync.js b/packages/csv-generate/lib/sync.js index be42baab6..5b84c39db 100644 --- a/packages/csv-generate/lib/sync.js +++ b/packages/csv-generate/lib/sync.js @@ -1,4 +1,3 @@ - /* CSV Generate - sync module @@ -6,38 +5,38 @@ Please look at the [project documentation](https://csv.js.org/generate/) for additional information. */ -import { Generator } from './index.js'; +import { Generator } from "./index.js"; -const generate = function(options){ - if(typeof options === 'string' && /\d+/.test(options)){ +const generate = function (options) { + if (typeof options === "string" && /\d+/.test(options)) { options = parseInt(options); } - if(Number.isInteger(options)){ - options = {length: options}; - }else if(typeof options !== 'object' || options === null){ - throw Error('Invalid Argument: options must be an object or an integer'); + if (Number.isInteger(options)) { + options = { length: options }; + } else if (typeof options !== "object" || options === null) { + throw Error("Invalid Argument: options must be an object or an integer"); } - if(!Number.isInteger(options.length)){ - throw Error('Invalid Argument: length is not defined'); + if (!Number.isInteger(options.length)) { + throw Error("Invalid Argument: length is not defined"); } const chunks = []; let work = true; const generator = new Generator(options); - generator.push = function(chunk){ - if(chunk === null){ - return work = false; + generator.push = function (chunk) { + if (chunk === null) { + return (work = false); } - chunks.push(chunk); + chunks.push(chunk); }; - while(work){ + while (work) { generator.__read(options.highWaterMark); } - if(!options.objectMode){ - return chunks.join(''); - }else{ + if (!options.objectMode) { + return chunks.join(""); + } else { return chunks; } }; // export default generate -export {generate}; +export { generate }; diff --git a/packages/csv-generate/package.json b/packages/csv-generate/package.json index f8939e3e2..d4c83e742 100644 --- a/packages/csv-generate/package.json +++ b/packages/csv-generate/package.json @@ -13,14 +13,18 @@ "bugs": "https://github.com/adaltas/node-csv-generate/issues", "author": "David Worms (https://www.adaltas.com)", "devDependencies": { - "@rollup/plugin-eslint": "^9.0.4", - "@rollup/plugin-node-resolve": "^15.2.1", + "@eslint/js": "^9.9.1", + "@rollup/plugin-node-resolve": "^15.2.3", "@types/mocha": "^10.0.7", "@types/node": "^22.5.0", "coffeescript": "~2.7.0", - "eslint": "^8.47.0", "each": "^2.7.0", + "eslint": "^9.9.1", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-mocha": "^10.5.0", + "eslint-plugin-prettier": "^5.2.1", "mocha": "~10.7.3", + "prettier": "^3.3.3", "rollup": "^4.21.0", "rollup-plugin-node-builtins": "^2.1.2", "rollup-plugin-node-globals": "^1.4.0", @@ -96,11 +100,8 @@ "build:rollup": "npx rollup -c", "build:ts": "cp lib/index.d.ts dist/cjs/index.d.cts && cp lib/stream.d.ts dist/cjs/stream.d.cts && cp lib/sync.d.ts dist/cjs/sync.d.cts && cp lib/*.ts dist/esm", "postbuild:ts": "find dist/cjs -name '*.d.cts' -exec sh -c \"sed -i \"s/\\.js'/\\.cjs'/g\" {} || sed -i '' \"s/\\.js'/\\.cjs'/g\" {}\" \\;", - "lint": "npm run lint:lib && npm run lint:samples && npm run lint:test", - "postlint": "tsc --noEmit true", - "lint:lib": "eslint --fix lib/*.js", - "lint:samples": "eslint --fix samples/*.js", - "lint:test": "coffeelint --fix test/*.coffee", + "lint:check": "eslint && tsc --noEmit true", + "lint:fix": "eslint --fix && tsc --noEmit true", "preversion": "npm run build && git add dist", "pretest": "npm run build", "test": "mocha 'test/**/*.{coffee,ts}'", diff --git a/packages/csv-generate/rollup.config.js b/packages/csv-generate/rollup.config.js index 6177f9031..77f852217 100644 --- a/packages/csv-generate/rollup.config.js +++ b/packages/csv-generate/rollup.config.js @@ -1,82 +1,102 @@ +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import globals from "rollup-plugin-node-globals"; +import builtins from "rollup-plugin-node-builtins"; +// import eslint from "@rollup/plugin-eslint"; -import { nodeResolve } from '@rollup/plugin-node-resolve'; -import globals from 'rollup-plugin-node-globals'; -import builtins from 'rollup-plugin-node-builtins'; -import eslint from '@rollup/plugin-eslint'; - -export default [{ - onwarn: function(warning, rollupWarn) { - // Not much we can do, Node.js `readable-stream/readable.js` and - // `readable-stream/duplex.js` from `rollup-plugin-node-builtins` raise this - // issue. - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - rollupWarn(warning); - }, - input: 'lib/index.js', - output: [ - { - file: `dist/esm/index.js`, - format: 'esm' - }, - { - file: `dist/iife/index.js`, - format: 'iife', - name: 'csv_generate' +export default [ + { + onwarn: function (warning, rollupWarn) { + // Not much we can do, Node.js `readable-stream/readable.js` and + // `readable-stream/duplex.js` from `rollup-plugin-node-builtins` raise this + // issue. + if (warning.code === "CIRCULAR_DEPENDENCY") return; + rollupWarn(warning); }, - { - file: `dist/umd/index.js`, - format: 'umd', - name: 'csv_generate' - }, - ], - plugins: [eslint({ - fix: true, - }), globals(), builtins(), nodeResolve()], -}, { - input: 'lib/index.js', - output: [ - { - file: `dist/cjs/index.cjs`, - format: 'cjs' - }, - ], - plugins: [eslint({ - fix: true, - }), nodeResolve()], -}, { - onwarn: function(warning, rollupWarn) { - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - rollupWarn(warning); + input: "lib/index.js", + output: [ + { + file: `dist/esm/index.js`, + format: "esm", + }, + { + file: `dist/iife/index.js`, + format: "iife", + name: "csv_generate", + }, + { + file: `dist/umd/index.js`, + format: "umd", + name: "csv_generate", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + globals(), + builtins(), + nodeResolve(), + ], }, - input: 'lib/sync.js', - output: [ - { - file: `dist/esm/sync.js`, - format: 'esm' - }, - { - file: `dist/iife/sync.js`, - format: 'iife', - name: 'csv_generate_sync' - }, - { - file: `dist/umd/sync.js`, - format: 'umd', - name: 'csv_generate_sync' - }, - ], - plugins: [eslint({ - fix: true, - }), globals(), builtins(), nodeResolve()], -}, { - input: 'lib/sync.js', - output: [ - { - file: `dist/cjs/sync.cjs`, - format: 'cjs' + { + input: "lib/index.js", + output: [ + { + file: `dist/cjs/index.cjs`, + format: "cjs", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + nodeResolve(), + ], + }, + { + onwarn: function (warning, rollupWarn) { + if (warning.code === "CIRCULAR_DEPENDENCY") return; + rollupWarn(warning); }, - ], - plugins: [eslint({ - fix: true, - }), nodeResolve()], -}]; + input: "lib/sync.js", + output: [ + { + file: `dist/esm/sync.js`, + format: "esm", + }, + { + file: `dist/iife/sync.js`, + format: "iife", + name: "csv_generate_sync", + }, + { + file: `dist/umd/sync.js`, + format: "umd", + name: "csv_generate_sync", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + globals(), + builtins(), + nodeResolve(), + ], + }, + { + input: "lib/sync.js", + output: [ + { + file: `dist/cjs/sync.cjs`, + format: "cjs", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + nodeResolve(), + ], + }, +]; diff --git a/packages/csv-generate/samples/api.callback.js b/packages/csv-generate/samples/api.callback.js index 09df30bc5..af5bd220b 100644 --- a/packages/csv-generate/samples/api.callback.js +++ b/packages/csv-generate/samples/api.callback.js @@ -1,15 +1,17 @@ +import assert from "node:assert"; +import { generate } from "csv-generate"; -import assert from 'node:assert'; -import { generate } from 'csv-generate'; - -generate({ - seed: 1, - objectMode: true, - columns: 2, - length: 2 -}, function(err, records){ - assert.deepEqual(records, [ - [ 'OMH', 'ONKCHhJmjadoA' ], - [ 'D', 'GeACHiN' ] - ]); -}); +generate( + { + seed: 1, + objectMode: true, + columns: 2, + length: 2, + }, + function (err, records) { + assert.deepEqual(records, [ + ["OMH", "ONKCHhJmjadoA"], + ["D", "GeACHiN"], + ]); + }, +); diff --git a/packages/csv-generate/samples/api.stream.js b/packages/csv-generate/samples/api.stream.js index da6c08753..076ad3651 100644 --- a/packages/csv-generate/samples/api.stream.js +++ b/packages/csv-generate/samples/api.stream.js @@ -1,6 +1,5 @@ - -import assert from 'node:assert'; -import { generate } from 'csv-generate'; +import assert from "node:assert"; +import { generate } from "csv-generate"; const records = []; // Initialize the generator @@ -8,22 +7,23 @@ generate({ seed: 1, objectMode: true, columns: 2, - length: 2 + length: 2, }) -// Use the readable stream api to consume generated records - .on('readable', function(){ - let record; while((record = this.read()) !== null){ + // Use the readable stream api to consume generated records + .on("readable", function () { + let record; + while ((record = this.read()) !== null) { records.push(record); } }) -// Catch any error - .on('error', function(err){ + // Catch any error + .on("error", function (err) { console.error(err); }) -// Test that the generated records matched the expected records - .on('end', function(){ + // Test that the generated records matched the expected records + .on("end", function () { assert.deepEqual(records, [ - [ 'OMH', 'ONKCHhJmjadoA' ], - [ 'D', 'GeACHiN' ] + ["OMH", "ONKCHhJmjadoA"], + ["D", "GeACHiN"], ]); }); diff --git a/packages/csv-generate/samples/api.sync.js b/packages/csv-generate/samples/api.sync.js index 92ccc6bb5..7205ef7e2 100644 --- a/packages/csv-generate/samples/api.sync.js +++ b/packages/csv-generate/samples/api.sync.js @@ -1,14 +1,13 @@ - -import assert from 'node:assert'; -import { generate } from 'csv-generate/sync'; +import assert from "node:assert"; +import { generate } from "csv-generate/sync"; const records = generate({ seed: 1, objectMode: true, columns: 2, - length: 2 + length: 2, }); assert.deepEqual(records, [ - [ 'OMH', 'ONKCHhJmjadoA' ], - [ 'D', 'GeACHiN' ] + ["OMH", "ONKCHhJmjadoA"], + ["D", "GeACHiN"], ]); diff --git a/packages/csv-generate/samples/options.objectmode.callback.js b/packages/csv-generate/samples/options.objectmode.callback.js index 09df30bc5..af5bd220b 100644 --- a/packages/csv-generate/samples/options.objectmode.callback.js +++ b/packages/csv-generate/samples/options.objectmode.callback.js @@ -1,15 +1,17 @@ +import assert from "node:assert"; +import { generate } from "csv-generate"; -import assert from 'node:assert'; -import { generate } from 'csv-generate'; - -generate({ - seed: 1, - objectMode: true, - columns: 2, - length: 2 -}, function(err, records){ - assert.deepEqual(records, [ - [ 'OMH', 'ONKCHhJmjadoA' ], - [ 'D', 'GeACHiN' ] - ]); -}); +generate( + { + seed: 1, + objectMode: true, + columns: 2, + length: 2, + }, + function (err, records) { + assert.deepEqual(records, [ + ["OMH", "ONKCHhJmjadoA"], + ["D", "GeACHiN"], + ]); + }, +); diff --git a/packages/csv-generate/samples/options.objectmode.stream.js b/packages/csv-generate/samples/options.objectmode.stream.js index d6654692c..9fe6c7d49 100644 --- a/packages/csv-generate/samples/options.objectmode.stream.js +++ b/packages/csv-generate/samples/options.objectmode.stream.js @@ -1,17 +1,14 @@ - -import assert from 'node:assert'; -import { generate } from 'csv-generate'; +import assert from "node:assert"; +import { generate } from "csv-generate"; generate({ seed: 1, objectMode: true, columns: 2, - length: 1 -}) - .on('readable', function(){ - let record; while((record = this.read()) !== null){ - assert.deepEqual(record, [ - 'OMH', 'ONKCHhJmjadoA' - ]); - } - }); + length: 1, +}).on("readable", function () { + let record; + while ((record = this.read()) !== null) { + assert.deepEqual(record, ["OMH", "ONKCHhJmjadoA"]); + } +}); diff --git a/packages/csv-generate/samples/pipe.js b/packages/csv-generate/samples/pipe.js index 731d0fcd1..70f91b8b3 100644 --- a/packages/csv-generate/samples/pipe.js +++ b/packages/csv-generate/samples/pipe.js @@ -1,8 +1,6 @@ - -import { generate } from 'csv-generate'; +import { generate } from "csv-generate"; generate({ - columns: ['int', 'bool'], - length: 2 -}) - .pipe(process.stdout); + columns: ["int", "bool"], + length: 2, +}).pipe(process.stdout); diff --git a/packages/csv-parse/.eslintrc.yml b/packages/csv-parse/.eslintrc.yml deleted file mode 100644 index 4581986eb..000000000 --- a/packages/csv-parse/.eslintrc.yml +++ /dev/null @@ -1,21 +0,0 @@ -env: - commonjs: true - es6: true - node: true -extends: "eslint:recommended" -globals: - Atomics: "readonly" - SharedArrayBuffer: "readonly" -parserOptions: - ecmaVersion: "latest" - sourceType: "module" -rules: - no-var: "error" - semi: "error" - indent: ["error", 2] - linebreak-style: ["error", "unix"] - no-multi-spaces: "error" - space-in-parens: "error" - no-multiple-empty-lines: "error" - prefer-const: "error" - no-use-before-define: "error" diff --git a/packages/csv-parse/.travis.yml b/packages/csv-parse/.travis.yml deleted file mode 100644 index 0a6e80cab..000000000 --- a/packages/csv-parse/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: node_js -node_js: - - "10" - - "11" - - "12" - - "14" diff --git a/packages/csv-parse/bench/async.iterator.js b/packages/csv-parse/bench/async.iterator.js index de74a36c7..6e64d31e8 100644 --- a/packages/csv-parse/bench/async.iterator.js +++ b/packages/csv-parse/bench/async.iterator.js @@ -16,7 +16,7 @@ const write = async function (length, target) { }).pipe( fs.createWriteStream(target, { highWaterMark: 64 * 64 * 1024, - }) + }), ); await finished(writter); }; @@ -61,12 +61,12 @@ const print = function (results) { pad(" throughput ", 15 + 2), ].join("|"), "|", - ].join("") + ].join(""), ); console.log( ["|", ["-".repeat(12), "-".repeat(17), "-".repeat(17)].join("|"), "|"].join( - "" - ) + "", + ), ); results.forEach(([length, nanoseconds, throughput]) => { console.log( @@ -78,7 +78,7 @@ const print = function (results) { ` ${pad(`${throughput}`, 15)} `, ].join("|"), "|", - ].join("") + ].join(""), ); }); console.log(""); @@ -96,7 +96,7 @@ const main = async function () { await write(length, target); const [seconds] = process.hrtime(time); console.log(`File ${target} created in ${seconds} seconds`); - }) + }), ); await Promise.all( await tests.map(async function ({ length, target }) { @@ -107,20 +107,20 @@ const main = async function () { const throughput = Math.round((length / nanoseconds) * NS_PER_SEC); console.log( "Benchmark time:", - `${nanoseconds} nanoseconds (${seconds} seconds)` + `${nanoseconds} nanoseconds (${seconds} seconds)`, ); console.log( "Benchmark throughput:", Math.round(throughput), - "records per second" + "records per second", ); report(length, nanoseconds, throughput); - }) + }), ); await Promise.all( await tests.map(async function ({ target }) { await dispose(target); - }) + }), ); const results = report(); print(results); diff --git a/packages/csv-parse/coffeelint.json b/packages/csv-parse/coffeelint.json deleted file mode 100644 index db57f258d..000000000 --- a/packages/csv-parse/coffeelint.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "arrow_spacing": { - "level": "ignore" - }, - "braces_spacing": { - "level": "ignore", - "spaces": 0, - "empty_object_spaces": 0 - }, - "camel_case_classes": { - "level": "error" - }, - "coffeescript_error": { - "level": "error" - }, - "colon_assignment_spacing": { - "level": "ignore", - "spacing": { - "left": 0, - "right": 0 - } - }, - "cyclomatic_complexity": { - "level": "ignore", - "value": 10 - }, - "duplicate_key": { - "level": "error" - }, - "empty_constructor_needs_parens": { - "level": "ignore" - }, - "ensure_comprehensions": { - "level": "warn" - }, - "eol_last": { - "level": "ignore" - }, - "indentation": { - "value": 2, - "level": "error" - }, - "line_endings": { - "level": "error", - "value": "unix" - }, - "max_line_length": { - "value": 80, - "level": "ignore", - "limitComments": true - }, - "missing_fat_arrows": { - "level": "ignore", - "is_strict": false - }, - "newlines_after_classes": { - "value": 3, - "level": "ignore" - }, - "no_backticks": { - "level": "error" - }, - "no_debugger": { - "level": "warn", - "console": false - }, - "no_empty_functions": { - "level": "ignore" - }, - "no_empty_param_list": { - "level": "ignore" - }, - "no_implicit_braces": { - "level": "ignore", - "strict": true - }, - "no_implicit_parens": { - "level": "ignore", - "strict": true - }, - "no_interpolation_in_single_quotes": { - "level": "ignore" - }, - "no_nested_string_interpolation": { - "level": "warn" - }, - "no_plusplus": { - "level": "ignore" - }, - "no_private_function_fat_arrows": { - "level": "warn" - }, - "no_stand_alone_at": { - "level": "ignore" - }, - "no_tabs": { - "level": "error" - }, - "no_this": { - "level": "ignore" - }, - "no_throwing_strings": { - "level": "error" - }, - "no_trailing_semicolons": { - "level": "error" - }, - "no_trailing_whitespace": { - "level": "error", - "allowed_in_comments": false, - "allowed_in_empty_lines": true - }, - "no_unnecessary_double_quotes": { - "level": "ignore" - }, - "no_unnecessary_fat_arrows": { - "level": "warn" - }, - "non_empty_constructor_needs_parens": { - "level": "ignore" - }, - "prefer_english_operator": { - "level": "ignore", - "doubleNotLevel": "ignore" - }, - "space_operators": { - "level": "ignore" - }, - "spacing_after_comma": { - "level": "ignore" - }, - "transform_messes_up_line_numbers": { - "level": "warn" - } -} diff --git a/packages/csv-parse/dist/cjs/index.cjs b/packages/csv-parse/dist/cjs/index.cjs index 4c6829ccb..df3086ab2 100644 --- a/packages/csv-parse/dist/cjs/index.cjs +++ b/packages/csv-parse/dist/cjs/index.cjs @@ -2,68 +2,72 @@ var stream = require('stream'); -const is_object = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = Buffer.isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = Buffer.isBuffer(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const normalize_columns_array = function(columns){ +const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object(column)) { + if (typeof column.name !== "string") { + throw new CsvError("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; -class ResizeableBuffer{ - constructor(size=100){ +class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(Buffer.isBuffer(val)){ + prepend(val) { + if (Buffer.isBuffer(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -71,44 +75,44 @@ class ResizeableBuffer{ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -123,7 +127,7 @@ const nl$1 = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal const space = 32; const tab = 9; -const init_state = function(options){ +const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -133,9 +137,14 @@ const init_state = function(options){ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: Buffer.isBuffer(options.escape) && Buffer.isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + Buffer.isBuffer(options.escape) && + Buffer.isBuffer(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -153,454 +162,700 @@ const init_state = function(options){ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts){ +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!Buffer.isBuffer(options.comment)){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!Buffer.isBuffer(options.comment)) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); } - if(typeof delimiter === 'string'){ + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!Buffer.isBuffer(delimiter) || delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!Buffer.isBuffer(delimiter) || delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!Buffer.isBuffer(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!Buffer.isBuffer(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(Buffer.isBuffer(options.objname)){ - if(options.objname.length === 0){ + } else if (Buffer.isBuffer(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!Buffer.isBuffer(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!Buffer.isBuffer(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || Buffer.isBuffer(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + Buffer.isBuffer(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! Buffer.isBuffer(rd)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !Buffer.isBuffer(rd)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); } - if(typeof rd === 'string'){ + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; -const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); +const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -611,21 +866,21 @@ const boms = { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; -const transform = function(original_options = {}) { +const transform = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options(original_options); return { @@ -633,10 +888,11 @@ const transform = function(original_options = {}) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -646,55 +902,73 @@ const transform = function(original_options = {}) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options({...this.original_options, encoding: encoding}); + this.options = normalize_options({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -703,51 +977,62 @@ const transform = function(original_options = {}) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -755,74 +1040,122 @@ const transform = function(original_options = {}) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -830,18 +1163,24 @@ const transform = function(original_options = {}) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -851,157 +1190,218 @@ const transform = function(original_options = {}) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -1012,45 +1412,53 @@ const transform = function(original_options = {}) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -1058,19 +1466,28 @@ const transform = function(original_options = {}) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -1078,92 +1495,98 @@ const transform = function(original_options = {}) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -1177,46 +1600,53 @@ const transform = function(original_options = {}) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -1224,13 +1654,13 @@ const transform = function(original_options = {}) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -1238,32 +1668,32 @@ const transform = function(original_options = {}) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -1273,152 +1703,181 @@ const transform = function(original_options = {}) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; +/* +CSV Parse + +Please look at the [project documentation](https://csv.js.org/parse/) for +additional information. +*/ + + class Parser extends stream.Transform { - constructor(opts = {}){ - super({...{readableObjectMode: true}, ...opts, encoding: null}); - this.api = transform({on_skip: (err, chunk) => { - this.emit('skip', err, chunk); - }, ...opts}); + constructor(opts = {}) { + super({ ...{ readableObjectMode: true }, ...opts, encoding: null }); + this.api = transform({ + on_skip: (err, chunk) => { + this.emit("skip", err, chunk); + }, + ...opts, + }); // Backward compatibility this.state = this.api.state; this.options = this.api.options; this.info = this.api.info; } // Implementation of `Transform._transform` - _transform(buf, _, callback){ - if(this.state.stop === true){ + _transform(buf, _, callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(buf, false, (record) => { - this.push(record); - }, () => { - this.push(null); - this.end(); - // Fix #333 and break #410 - // ko: api.stream.iterator.coffee - // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) - // ko: api.stream.finished # aborted (with Readable) - // this.destroy() - // Fix #410 and partially break #333 - // ok: api.stream.iterator.coffee - // ok: api.stream.finished # aborted (with generate()) - // broken: api.stream.finished # aborted (with Readable) - this.on('end', this.destroy); - }); - if(err !== undefined){ + const err = this.api.parse( + buf, + false, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.end(); + // Fix #333 and break #410 + // ko: api.stream.iterator.coffee + // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) + // ko: api.stream.finished # aborted (with Readable) + // this.destroy() + // Fix #410 and partially break #333 + // ok: api.stream.iterator.coffee + // ok: api.stream.finished # aborted (with generate()) + // broken: api.stream.finished # aborted (with Readable) + this.on("end", this.destroy); + }, + ); + if (err !== undefined) { this.state.stop = true; } callback(err); } // Implementation of `Transform._flush` - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(undefined, true, (record) => { - this.push(record); - }, () => { - this.push(null); - this.on('end', this.destroy); - }); + const err = this.api.parse( + undefined, + true, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.on("end", this.destroy); + }, + ); callback(err); } } -const parse = function(){ +const parse = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (typeof argument === 'string' || Buffer.isBuffer(argument))){ + if ( + data === undefined && + (typeof argument === "string" || Buffer.isBuffer(argument)) + ) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` - ], options || {}); + } else { + throw new CsvError( + "CSV_INVALID_ARGUMENT", + ["Invalid argument:", `got ${JSON.stringify(argument)} at index ${i}`], + options || {}, + ); } } const parser = new Parser(options); - if(callback){ - const records = options === undefined || options.objname === undefined ? [] : {}; - parser.on('readable', function(){ + if (callback) { + const records = + options === undefined || options.objname === undefined ? [] : {}; + parser.on("readable", function () { let record; - while((record = this.read()) !== null){ - if(options === undefined || options.objname === undefined){ + while ((record = this.read()) !== null) { + if (options === undefined || options.objname === undefined) { records.push(record); - }else { + } else { records[record[0]] = record[1]; } } }); - parser.on('error', function(err){ + parser.on("error", function (err) { callback(err, undefined, parser.api.__infoDataSet()); }); - parser.on('end', function(){ + parser.on("end", function () { callback(undefined, records, parser.api.__infoDataSet()); }); } - if(data !== undefined){ - const writer = function(){ + if (data !== undefined) { + const writer = function () { parser.write(data); parser.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv-parse/dist/cjs/sync.cjs b/packages/csv-parse/dist/cjs/sync.cjs index cf35099a3..dc6113ad3 100644 --- a/packages/csv-parse/dist/cjs/sync.cjs +++ b/packages/csv-parse/dist/cjs/sync.cjs @@ -2,66 +2,70 @@ class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = Buffer.isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = Buffer.isBuffer(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const is_object = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; -const normalize_columns_array = function(columns){ +const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object(column)) { + if (typeof column.name !== "string") { + throw new CsvError("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; -class ResizeableBuffer{ - constructor(size=100){ +class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(Buffer.isBuffer(val)){ + prepend(val) { + if (Buffer.isBuffer(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -69,44 +73,44 @@ class ResizeableBuffer{ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -121,7 +125,7 @@ const nl$1 = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal const space = 32; const tab = 9; -const init_state = function(options){ +const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -131,9 +135,14 @@ const init_state = function(options){ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: Buffer.isBuffer(options.escape) && Buffer.isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + Buffer.isBuffer(options.escape) && + Buffer.isBuffer(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -151,454 +160,700 @@ const init_state = function(options){ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts){ +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!Buffer.isBuffer(options.comment)){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!Buffer.isBuffer(options.comment)) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); } - if(typeof delimiter === 'string'){ + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!Buffer.isBuffer(delimiter) || delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!Buffer.isBuffer(delimiter) || delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!Buffer.isBuffer(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!Buffer.isBuffer(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(Buffer.isBuffer(options.objname)){ - if(options.objname.length === 0){ + } else if (Buffer.isBuffer(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!Buffer.isBuffer(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!Buffer.isBuffer(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || Buffer.isBuffer(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + Buffer.isBuffer(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! Buffer.isBuffer(rd)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !Buffer.isBuffer(rd)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); } - if(typeof rd === 'string'){ + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; -const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); +const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -609,21 +864,21 @@ const boms = { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; -const transform = function(original_options = {}) { +const transform = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options(original_options); return { @@ -631,10 +886,11 @@ const transform = function(original_options = {}) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -644,55 +900,73 @@ const transform = function(original_options = {}) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options({...this.original_options, encoding: encoding}); + this.options = normalize_options({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -701,51 +975,62 @@ const transform = function(original_options = {}) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -753,74 +1038,122 @@ const transform = function(original_options = {}) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -828,18 +1161,24 @@ const transform = function(original_options = {}) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -849,157 +1188,218 @@ const transform = function(original_options = {}) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -1010,45 +1410,53 @@ const transform = function(original_options = {}) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -1056,19 +1464,28 @@ const transform = function(original_options = {}) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -1076,92 +1493,98 @@ const transform = function(original_options = {}) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -1175,46 +1598,53 @@ const transform = function(original_options = {}) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -1222,13 +1652,13 @@ const transform = function(original_options = {}) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -1236,32 +1666,32 @@ const transform = function(original_options = {}) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -1271,71 +1701,73 @@ const transform = function(original_options = {}) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; -const parse = function(data, opts={}){ - if(typeof data === 'string'){ +const parse = function (data, opts = {}) { + if (typeof data === "string") { data = Buffer.from(data); } const records = opts && opts.objname ? {} : []; const parser = transform(opts); const push = (record) => { - if(parser.options.objname === undefined) - records.push(record); + if (parser.options.objname === undefined) records.push(record); else { records[record[0]] = record[1]; } }; const close = () => {}; const err1 = parser.parse(data, false, push, close); - if(err1 !== undefined) throw err1; + if (err1 !== undefined) throw err1; const err2 = parser.parse(undefined, true, push, close); - if(err2 !== undefined) throw err2; + if (err2 !== undefined) throw err2; return records; }; diff --git a/packages/csv-parse/dist/esm/index.js b/packages/csv-parse/dist/esm/index.js index a8f1e23cc..5b396c3a7 100644 --- a/packages/csv-parse/dist/esm/index.js +++ b/packages/csv-parse/dist/esm/index.js @@ -2000,7 +2000,7 @@ EventEmitter.init = function() { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5124,68 +5124,72 @@ Stream.prototype.pipe = function(dest, options) { return dest; }; -const is_object = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const normalize_columns_array = function(columns){ +const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object(column)) { + if (typeof column.name !== "string") { + throw new CsvError("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; -class ResizeableBuffer{ - constructor(size=100){ +class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer(val)){ + prepend(val) { + if (isBuffer(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -5193,44 +5197,44 @@ class ResizeableBuffer{ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -5245,7 +5249,7 @@ const nl$1 = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal const space = 32; const tab = 9; -const init_state = function(options){ +const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -5255,9 +5259,14 @@ const init_state = function(options){ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer(options.escape) && isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer(options.escape) && + isBuffer(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -5275,454 +5284,700 @@ const init_state = function(options){ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts){ +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer(options.comment)){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer(options.comment)) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer(delimiter) || delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer(delimiter) || delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer(rd)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer(rd)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; -const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); +const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -5733,21 +5988,21 @@ const boms = { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; -const transform = function(original_options = {}) { +const transform = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options(original_options); return { @@ -5755,10 +6010,11 @@ const transform = function(original_options = {}) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -5768,55 +6024,73 @@ const transform = function(original_options = {}) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options({...this.original_options, encoding: encoding}); + this.options = normalize_options({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -5825,51 +6099,62 @@ const transform = function(original_options = {}) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -5877,74 +6162,122 @@ const transform = function(original_options = {}) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -5952,18 +6285,24 @@ const transform = function(original_options = {}) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -5973,157 +6312,218 @@ const transform = function(original_options = {}) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -6134,45 +6534,53 @@ const transform = function(original_options = {}) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -6180,19 +6588,28 @@ const transform = function(original_options = {}) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -6200,92 +6617,98 @@ const transform = function(original_options = {}) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -6299,46 +6722,53 @@ const transform = function(original_options = {}) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -6346,13 +6776,13 @@ const transform = function(original_options = {}) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -6360,32 +6790,32 @@ const transform = function(original_options = {}) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -6395,152 +6825,173 @@ const transform = function(original_options = {}) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; class Parser extends Transform { - constructor(opts = {}){ - super({...{readableObjectMode: true}, ...opts, encoding: null}); - this.api = transform({on_skip: (err, chunk) => { - this.emit('skip', err, chunk); - }, ...opts}); + constructor(opts = {}) { + super({ ...{ readableObjectMode: true }, ...opts, encoding: null }); + this.api = transform({ + on_skip: (err, chunk) => { + this.emit("skip", err, chunk); + }, + ...opts, + }); // Backward compatibility this.state = this.api.state; this.options = this.api.options; this.info = this.api.info; } // Implementation of `Transform._transform` - _transform(buf, _, callback){ - if(this.state.stop === true){ + _transform(buf, _, callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(buf, false, (record) => { - this.push(record); - }, () => { - this.push(null); - this.end(); - // Fix #333 and break #410 - // ko: api.stream.iterator.coffee - // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) - // ko: api.stream.finished # aborted (with Readable) - // this.destroy() - // Fix #410 and partially break #333 - // ok: api.stream.iterator.coffee - // ok: api.stream.finished # aborted (with generate()) - // broken: api.stream.finished # aborted (with Readable) - this.on('end', this.destroy); - }); - if(err !== undefined){ + const err = this.api.parse( + buf, + false, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.end(); + // Fix #333 and break #410 + // ko: api.stream.iterator.coffee + // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) + // ko: api.stream.finished # aborted (with Readable) + // this.destroy() + // Fix #410 and partially break #333 + // ok: api.stream.iterator.coffee + // ok: api.stream.finished # aborted (with generate()) + // broken: api.stream.finished # aborted (with Readable) + this.on("end", this.destroy); + }, + ); + if (err !== undefined) { this.state.stop = true; } callback(err); } // Implementation of `Transform._flush` - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(undefined, true, (record) => { - this.push(record); - }, () => { - this.push(null); - this.on('end', this.destroy); - }); + const err = this.api.parse( + undefined, + true, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.on("end", this.destroy); + }, + ); callback(err); } } -const parse = function(){ +const parse = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (typeof argument === 'string' || isBuffer(argument))){ + if ( + data === undefined && + (typeof argument === "string" || isBuffer(argument)) + ) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` - ], options || {}); + } else { + throw new CsvError( + "CSV_INVALID_ARGUMENT", + ["Invalid argument:", `got ${JSON.stringify(argument)} at index ${i}`], + options || {}, + ); } } const parser = new Parser(options); - if(callback){ - const records = options === undefined || options.objname === undefined ? [] : {}; - parser.on('readable', function(){ + if (callback) { + const records = + options === undefined || options.objname === undefined ? [] : {}; + parser.on("readable", function () { let record; - while((record = this.read()) !== null){ - if(options === undefined || options.objname === undefined){ + while ((record = this.read()) !== null) { + if (options === undefined || options.objname === undefined) { records.push(record); - }else { + } else { records[record[0]] = record[1]; } } }); - parser.on('error', function(err){ + parser.on("error", function (err) { callback(err, undefined, parser.api.__infoDataSet()); }); - parser.on('end', function(){ + parser.on("end", function () { callback(undefined, records, parser.api.__infoDataSet()); }); } - if(data !== undefined){ - const writer = function(){ + if (data !== undefined) { + const writer = function () { parser.write(data); parser.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv-parse/dist/esm/sync.js b/packages/csv-parse/dist/esm/sync.js index 65ab56f12..fc824a426 100644 --- a/packages/csv-parse/dist/esm/sync.js +++ b/packages/csv-parse/dist/esm/sync.js @@ -1972,66 +1972,70 @@ function isSlowBuffer (obj) { class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const is_object = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; -const normalize_columns_array = function(columns){ +const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object(column)) { + if (typeof column.name !== "string") { + throw new CsvError("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; -class ResizeableBuffer{ - constructor(size=100){ +class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer(val)){ + prepend(val) { + if (isBuffer(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -2039,44 +2043,44 @@ class ResizeableBuffer{ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -2091,7 +2095,7 @@ const nl$1 = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal const space = 32; const tab = 9; -const init_state = function(options){ +const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -2101,9 +2105,14 @@ const init_state = function(options){ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer(options.escape) && isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer(options.escape) && + isBuffer(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -2121,454 +2130,700 @@ const init_state = function(options){ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts){ +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer(options.comment)){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer(options.comment)) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer(delimiter) || delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer(delimiter) || delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer(rd)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer(rd)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; -const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); +const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -2579,21 +2834,21 @@ const boms = { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; -const transform = function(original_options = {}) { +const transform = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options(original_options); return { @@ -2601,10 +2856,11 @@ const transform = function(original_options = {}) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -2614,55 +2870,73 @@ const transform = function(original_options = {}) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options({...this.original_options, encoding: encoding}); + this.options = normalize_options({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -2671,51 +2945,62 @@ const transform = function(original_options = {}) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -2723,74 +3008,122 @@ const transform = function(original_options = {}) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -2798,18 +3131,24 @@ const transform = function(original_options = {}) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -2819,157 +3158,218 @@ const transform = function(original_options = {}) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -2980,45 +3380,53 @@ const transform = function(original_options = {}) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -3026,19 +3434,28 @@ const transform = function(original_options = {}) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -3046,92 +3463,98 @@ const transform = function(original_options = {}) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -3145,46 +3568,53 @@ const transform = function(original_options = {}) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -3192,13 +3622,13 @@ const transform = function(original_options = {}) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -3206,32 +3636,32 @@ const transform = function(original_options = {}) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -3241,71 +3671,73 @@ const transform = function(original_options = {}) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; -const parse = function(data, opts={}){ - if(typeof data === 'string'){ +const parse = function (data, opts = {}) { + if (typeof data === "string") { data = Buffer.from(data); } const records = opts && opts.objname ? {} : []; const parser = transform(opts); const push = (record) => { - if(parser.options.objname === undefined) - records.push(record); + if (parser.options.objname === undefined) records.push(record); else { records[record[0]] = record[1]; } }; const close = () => {}; const err1 = parser.parse(data, false, push, close); - if(err1 !== undefined) throw err1; + if (err1 !== undefined) throw err1; const err2 = parser.parse(undefined, true, push, close); - if(err2 !== undefined) throw err2; + if (err2 !== undefined) throw err2; return records; }; diff --git a/packages/csv-parse/dist/iife/index.js b/packages/csv-parse/dist/iife/index.js index fdf8ad2c3..16f849e6f 100644 --- a/packages/csv-parse/dist/iife/index.js +++ b/packages/csv-parse/dist/iife/index.js @@ -2003,7 +2003,7 @@ var csv_parse = (function (exports) { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5127,68 +5127,72 @@ var csv_parse = (function (exports) { return dest; }; - const is_object = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const normalize_columns_array = function(columns){ + const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object(column)) { + if (typeof column.name !== "string") { + throw new CsvError("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; - class ResizeableBuffer{ - constructor(size=100){ + class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer(val)){ + prepend(val) { + if (isBuffer(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -5196,44 +5200,44 @@ var csv_parse = (function (exports) { val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -5248,7 +5252,7 @@ var csv_parse = (function (exports) { const space = 32; const tab = 9; - const init_state = function(options){ + const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -5258,9 +5262,14 @@ var csv_parse = (function (exports) { error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer(options.escape) && isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer(options.escape) && + isBuffer(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -5278,454 +5287,700 @@ var csv_parse = (function (exports) { record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts){ + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer(options.comment)){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer(options.comment)) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer(delimiter) || delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer(delimiter) || delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer(rd)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer(rd)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; - const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); + const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -5736,21 +5991,21 @@ var csv_parse = (function (exports) { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; - const transform = function(original_options = {}) { + const transform = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options(original_options); return { @@ -5758,10 +6013,11 @@ var csv_parse = (function (exports) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -5771,55 +6027,73 @@ var csv_parse = (function (exports) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options({...this.original_options, encoding: encoding}); + this.options = normalize_options({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -5828,51 +6102,62 @@ var csv_parse = (function (exports) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -5880,74 +6165,122 @@ var csv_parse = (function (exports) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -5955,18 +6288,24 @@ var csv_parse = (function (exports) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -5976,157 +6315,218 @@ var csv_parse = (function (exports) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -6137,45 +6537,53 @@ var csv_parse = (function (exports) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -6183,19 +6591,28 @@ var csv_parse = (function (exports) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -6203,92 +6620,98 @@ var csv_parse = (function (exports) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -6302,46 +6725,53 @@ var csv_parse = (function (exports) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -6349,13 +6779,13 @@ var csv_parse = (function (exports) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -6363,32 +6793,32 @@ var csv_parse = (function (exports) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -6398,152 +6828,173 @@ var csv_parse = (function (exports) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; class Parser extends Transform { - constructor(opts = {}){ - super({...{readableObjectMode: true}, ...opts, encoding: null}); - this.api = transform({on_skip: (err, chunk) => { - this.emit('skip', err, chunk); - }, ...opts}); + constructor(opts = {}) { + super({ ...{ readableObjectMode: true }, ...opts, encoding: null }); + this.api = transform({ + on_skip: (err, chunk) => { + this.emit("skip", err, chunk); + }, + ...opts, + }); // Backward compatibility this.state = this.api.state; this.options = this.api.options; this.info = this.api.info; } // Implementation of `Transform._transform` - _transform(buf, _, callback){ - if(this.state.stop === true){ + _transform(buf, _, callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(buf, false, (record) => { - this.push(record); - }, () => { - this.push(null); - this.end(); - // Fix #333 and break #410 - // ko: api.stream.iterator.coffee - // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) - // ko: api.stream.finished # aborted (with Readable) - // this.destroy() - // Fix #410 and partially break #333 - // ok: api.stream.iterator.coffee - // ok: api.stream.finished # aborted (with generate()) - // broken: api.stream.finished # aborted (with Readable) - this.on('end', this.destroy); - }); - if(err !== undefined){ + const err = this.api.parse( + buf, + false, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.end(); + // Fix #333 and break #410 + // ko: api.stream.iterator.coffee + // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) + // ko: api.stream.finished # aborted (with Readable) + // this.destroy() + // Fix #410 and partially break #333 + // ok: api.stream.iterator.coffee + // ok: api.stream.finished # aborted (with generate()) + // broken: api.stream.finished # aborted (with Readable) + this.on("end", this.destroy); + }, + ); + if (err !== undefined) { this.state.stop = true; } callback(err); } // Implementation of `Transform._flush` - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(undefined, true, (record) => { - this.push(record); - }, () => { - this.push(null); - this.on('end', this.destroy); - }); + const err = this.api.parse( + undefined, + true, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.on("end", this.destroy); + }, + ); callback(err); } } - const parse = function(){ + const parse = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (typeof argument === 'string' || isBuffer(argument))){ + if ( + data === undefined && + (typeof argument === "string" || isBuffer(argument)) + ) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` - ], options || {}); + } else { + throw new CsvError( + "CSV_INVALID_ARGUMENT", + ["Invalid argument:", `got ${JSON.stringify(argument)} at index ${i}`], + options || {}, + ); } } const parser = new Parser(options); - if(callback){ - const records = options === undefined || options.objname === undefined ? [] : {}; - parser.on('readable', function(){ + if (callback) { + const records = + options === undefined || options.objname === undefined ? [] : {}; + parser.on("readable", function () { let record; - while((record = this.read()) !== null){ - if(options === undefined || options.objname === undefined){ + while ((record = this.read()) !== null) { + if (options === undefined || options.objname === undefined) { records.push(record); - }else { + } else { records[record[0]] = record[1]; } } }); - parser.on('error', function(err){ + parser.on("error", function (err) { callback(err, undefined, parser.api.__infoDataSet()); }); - parser.on('end', function(){ + parser.on("end", function () { callback(undefined, records, parser.api.__infoDataSet()); }); } - if(data !== undefined){ - const writer = function(){ + if (data !== undefined) { + const writer = function () { parser.write(data); parser.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv-parse/dist/iife/sync.js b/packages/csv-parse/dist/iife/sync.js index b12179d27..bf710048f 100644 --- a/packages/csv-parse/dist/iife/sync.js +++ b/packages/csv-parse/dist/iife/sync.js @@ -1975,66 +1975,70 @@ var csv_parse_sync = (function (exports) { class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const is_object = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; - const normalize_columns_array = function(columns){ + const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object(column)) { + if (typeof column.name !== "string") { + throw new CsvError("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; - class ResizeableBuffer{ - constructor(size=100){ + class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer(val)){ + prepend(val) { + if (isBuffer(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -2042,44 +2046,44 @@ var csv_parse_sync = (function (exports) { val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -2094,7 +2098,7 @@ var csv_parse_sync = (function (exports) { const space = 32; const tab = 9; - const init_state = function(options){ + const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -2104,9 +2108,14 @@ var csv_parse_sync = (function (exports) { error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer(options.escape) && isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer(options.escape) && + isBuffer(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -2124,454 +2133,700 @@ var csv_parse_sync = (function (exports) { record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts){ + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer(options.comment)){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer(options.comment)) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer(delimiter) || delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer(delimiter) || delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer(rd)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer(rd)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; - const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); + const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -2582,21 +2837,21 @@ var csv_parse_sync = (function (exports) { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; - const transform = function(original_options = {}) { + const transform = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options(original_options); return { @@ -2604,10 +2859,11 @@ var csv_parse_sync = (function (exports) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -2617,55 +2873,73 @@ var csv_parse_sync = (function (exports) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options({...this.original_options, encoding: encoding}); + this.options = normalize_options({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -2674,51 +2948,62 @@ var csv_parse_sync = (function (exports) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -2726,74 +3011,122 @@ var csv_parse_sync = (function (exports) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -2801,18 +3134,24 @@ var csv_parse_sync = (function (exports) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -2822,157 +3161,218 @@ var csv_parse_sync = (function (exports) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -2983,45 +3383,53 @@ var csv_parse_sync = (function (exports) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -3029,19 +3437,28 @@ var csv_parse_sync = (function (exports) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -3049,92 +3466,98 @@ var csv_parse_sync = (function (exports) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -3148,46 +3571,53 @@ var csv_parse_sync = (function (exports) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -3195,13 +3625,13 @@ var csv_parse_sync = (function (exports) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -3209,32 +3639,32 @@ var csv_parse_sync = (function (exports) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -3244,71 +3674,73 @@ var csv_parse_sync = (function (exports) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; - const parse = function(data, opts={}){ - if(typeof data === 'string'){ + const parse = function (data, opts = {}) { + if (typeof data === "string") { data = Buffer.from(data); } const records = opts && opts.objname ? {} : []; const parser = transform(opts); const push = (record) => { - if(parser.options.objname === undefined) - records.push(record); + if (parser.options.objname === undefined) records.push(record); else { records[record[0]] = record[1]; } }; const close = () => {}; const err1 = parser.parse(data, false, push, close); - if(err1 !== undefined) throw err1; + if (err1 !== undefined) throw err1; const err2 = parser.parse(undefined, true, push, close); - if(err2 !== undefined) throw err2; + if (err2 !== undefined) throw err2; return records; }; diff --git a/packages/csv-parse/dist/umd/index.js b/packages/csv-parse/dist/umd/index.js index 4d3314f0c..688695bd8 100644 --- a/packages/csv-parse/dist/umd/index.js +++ b/packages/csv-parse/dist/umd/index.js @@ -2006,7 +2006,7 @@ this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5130,68 +5130,72 @@ return dest; }; - const is_object = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const normalize_columns_array = function(columns){ + const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object(column)) { + if (typeof column.name !== "string") { + throw new CsvError("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; - class ResizeableBuffer{ - constructor(size=100){ + class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer(val)){ + prepend(val) { + if (isBuffer(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -5199,44 +5203,44 @@ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -5251,7 +5255,7 @@ const space = 32; const tab = 9; - const init_state = function(options){ + const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -5261,9 +5265,14 @@ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer(options.escape) && isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer(options.escape) && + isBuffer(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -5281,454 +5290,700 @@ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts){ + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer(options.comment)){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer(options.comment)) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer(delimiter) || delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer(delimiter) || delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer(rd)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer(rd)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; - const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); + const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -5739,21 +5994,21 @@ // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; - const transform = function(original_options = {}) { + const transform = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options(original_options); return { @@ -5761,10 +6016,11 @@ original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -5774,55 +6030,73 @@ // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options({...this.original_options, encoding: encoding}); + this.options = normalize_options({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -5831,51 +6105,62 @@ } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -5883,74 +6168,122 @@ } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -5958,18 +6291,24 @@ continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -5979,157 +6318,218 @@ pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -6140,45 +6540,53 @@ } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -6186,19 +6594,28 @@ } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -6206,92 +6623,98 @@ this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -6305,46 +6728,53 @@ // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -6352,13 +6782,13 @@ } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -6366,32 +6796,32 @@ } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -6401,152 +6831,173 @@ } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; class Parser extends Transform { - constructor(opts = {}){ - super({...{readableObjectMode: true}, ...opts, encoding: null}); - this.api = transform({on_skip: (err, chunk) => { - this.emit('skip', err, chunk); - }, ...opts}); + constructor(opts = {}) { + super({ ...{ readableObjectMode: true }, ...opts, encoding: null }); + this.api = transform({ + on_skip: (err, chunk) => { + this.emit("skip", err, chunk); + }, + ...opts, + }); // Backward compatibility this.state = this.api.state; this.options = this.api.options; this.info = this.api.info; } // Implementation of `Transform._transform` - _transform(buf, _, callback){ - if(this.state.stop === true){ + _transform(buf, _, callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(buf, false, (record) => { - this.push(record); - }, () => { - this.push(null); - this.end(); - // Fix #333 and break #410 - // ko: api.stream.iterator.coffee - // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) - // ko: api.stream.finished # aborted (with Readable) - // this.destroy() - // Fix #410 and partially break #333 - // ok: api.stream.iterator.coffee - // ok: api.stream.finished # aborted (with generate()) - // broken: api.stream.finished # aborted (with Readable) - this.on('end', this.destroy); - }); - if(err !== undefined){ + const err = this.api.parse( + buf, + false, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.end(); + // Fix #333 and break #410 + // ko: api.stream.iterator.coffee + // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) + // ko: api.stream.finished # aborted (with Readable) + // this.destroy() + // Fix #410 and partially break #333 + // ok: api.stream.iterator.coffee + // ok: api.stream.finished # aborted (with generate()) + // broken: api.stream.finished # aborted (with Readable) + this.on("end", this.destroy); + }, + ); + if (err !== undefined) { this.state.stop = true; } callback(err); } // Implementation of `Transform._flush` - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(undefined, true, (record) => { - this.push(record); - }, () => { - this.push(null); - this.on('end', this.destroy); - }); + const err = this.api.parse( + undefined, + true, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.on("end", this.destroy); + }, + ); callback(err); } } - const parse = function(){ + const parse = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (typeof argument === 'string' || isBuffer(argument))){ + if ( + data === undefined && + (typeof argument === "string" || isBuffer(argument)) + ) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` - ], options || {}); + } else { + throw new CsvError( + "CSV_INVALID_ARGUMENT", + ["Invalid argument:", `got ${JSON.stringify(argument)} at index ${i}`], + options || {}, + ); } } const parser = new Parser(options); - if(callback){ - const records = options === undefined || options.objname === undefined ? [] : {}; - parser.on('readable', function(){ + if (callback) { + const records = + options === undefined || options.objname === undefined ? [] : {}; + parser.on("readable", function () { let record; - while((record = this.read()) !== null){ - if(options === undefined || options.objname === undefined){ + while ((record = this.read()) !== null) { + if (options === undefined || options.objname === undefined) { records.push(record); - }else { + } else { records[record[0]] = record[1]; } } }); - parser.on('error', function(err){ + parser.on("error", function (err) { callback(err, undefined, parser.api.__infoDataSet()); }); - parser.on('end', function(){ + parser.on("end", function () { callback(undefined, records, parser.api.__infoDataSet()); }); } - if(data !== undefined){ - const writer = function(){ + if (data !== undefined) { + const writer = function () { parser.write(data); parser.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv-parse/dist/umd/sync.js b/packages/csv-parse/dist/umd/sync.js index 6aaccb8d4..8aef129fe 100644 --- a/packages/csv-parse/dist/umd/sync.js +++ b/packages/csv-parse/dist/umd/sync.js @@ -1978,66 +1978,70 @@ class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const is_object = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; - const normalize_columns_array = function(columns){ + const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object(column)) { + if (typeof column.name !== "string") { + throw new CsvError("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; - class ResizeableBuffer{ - constructor(size=100){ + class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer(val)){ + prepend(val) { + if (isBuffer(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -2045,44 +2049,44 @@ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -2097,7 +2101,7 @@ const space = 32; const tab = 9; - const init_state = function(options){ + const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -2107,9 +2111,14 @@ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer(options.escape) && isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer(options.escape) && + isBuffer(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -2127,454 +2136,700 @@ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts){ + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer(options.comment)){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer(options.comment)) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer(delimiter) || delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer(delimiter) || delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer(rd)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer(rd)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; - const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); + const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -2585,21 +2840,21 @@ // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; - const transform = function(original_options = {}) { + const transform = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options(original_options); return { @@ -2607,10 +2862,11 @@ original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -2620,55 +2876,73 @@ // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options({...this.original_options, encoding: encoding}); + this.options = normalize_options({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -2677,51 +2951,62 @@ } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -2729,74 +3014,122 @@ } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -2804,18 +3137,24 @@ continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -2825,157 +3164,218 @@ pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -2986,45 +3386,53 @@ } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -3032,19 +3440,28 @@ } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -3052,92 +3469,98 @@ this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -3151,46 +3574,53 @@ // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -3198,13 +3628,13 @@ } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -3212,32 +3642,32 @@ } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -3247,71 +3677,73 @@ } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; - const parse = function(data, opts={}){ - if(typeof data === 'string'){ + const parse = function (data, opts = {}) { + if (typeof data === "string") { data = Buffer.from(data); } const records = opts && opts.objname ? {} : []; const parser = transform(opts); const push = (record) => { - if(parser.options.objname === undefined) - records.push(record); + if (parser.options.objname === undefined) records.push(record); else { records[record[0]] = record[1]; } }; const close = () => {}; const err1 = parser.parse(data, false, push, close); - if(err1 !== undefined) throw err1; + if (err1 !== undefined) throw err1; const err2 = parser.parse(undefined, true, push, close); - if(err2 !== undefined) throw err2; + if (err2 !== undefined) throw err2; return records; }; diff --git a/packages/csv-parse/eslint.config.js b/packages/csv-parse/eslint.config.js new file mode 100644 index 000000000..c129c277f --- /dev/null +++ b/packages/csv-parse/eslint.config.js @@ -0,0 +1,16 @@ +import globals from "globals"; +import js from "@eslint/js"; +import mocha from "eslint-plugin-mocha"; +import prettier from "eslint-plugin-prettier/recommended"; + +export default [ + { + ignores: ["dist/**"], + }, + { + languageOptions: { globals: { ...globals.node } }, + }, + js.configs.recommended, + mocha.configs.flat.recommended, + prettier, +]; diff --git a/packages/csv-parse/lib/api/CsvError.js b/packages/csv-parse/lib/api/CsvError.js index 1af83534c..b44229128 100644 --- a/packages/csv-parse/lib/api/CsvError.js +++ b/packages/csv-parse/lib/api/CsvError.js @@ -1,19 +1,22 @@ - class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = Buffer.isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = Buffer.isBuffer(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -export {CsvError}; +export { CsvError }; diff --git a/packages/csv-parse/lib/api/index.js b/packages/csv-parse/lib/api/index.js index 0fc5e3f8b..a1ba1eb02 100644 --- a/packages/csv-parse/lib/api/index.js +++ b/packages/csv-parse/lib/api/index.js @@ -1,11 +1,13 @@ +import { normalize_columns_array } from "./normalize_columns_array.js"; +import { init_state } from "./init_state.js"; +import { normalize_options } from "./normalize_options.js"; +import { CsvError } from "./CsvError.js"; -import {normalize_columns_array} from './normalize_columns_array.js'; -import {init_state} from './init_state.js'; -import {normalize_options} from './normalize_options.js'; -import {CsvError} from './CsvError.js'; - -const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); +const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -16,21 +18,21 @@ const boms = { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; -const transform = function(original_options = {}) { +const transform = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options(original_options); return { @@ -38,10 +40,11 @@ const transform = function(original_options = {}) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -51,55 +54,73 @@ const transform = function(original_options = {}) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else{ + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else{ + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else{ - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options({...this.original_options, encoding: encoding}); + this.options = normalize_options({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -108,51 +129,62 @@ const transform = function(original_options = {}) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else{ + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else{ + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -160,74 +192,122 @@ const transform = function(original_options = {}) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else{ + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else{ - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else{ + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else{ + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -235,18 +315,24 @@ const transform = function(original_options = {}) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -256,157 +342,218 @@ const transform = function(original_options = {}) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else{ - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else{ + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else{ + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else{ + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -417,45 +564,53 @@ const transform = function(original_options = {}) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else{ + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else{ - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else{ + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -463,19 +618,28 @@ const transform = function(original_options = {}) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -483,92 +647,98 @@ const transform = function(original_options = {}) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -582,46 +752,53 @@ const transform = function(original_options = {}) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -629,13 +806,13 @@ const transform = function(original_options = {}) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -643,32 +820,32 @@ const transform = function(original_options = {}) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -678,52 +855,54 @@ const transform = function(original_options = {}) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else{ + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; - -export {transform, CsvError}; +export { transform, CsvError }; diff --git a/packages/csv-parse/lib/api/init_state.js b/packages/csv-parse/lib/api/init_state.js index e2a68c354..dce8b2580 100644 --- a/packages/csv-parse/lib/api/init_state.js +++ b/packages/csv-parse/lib/api/init_state.js @@ -1,5 +1,4 @@ - -import ResizeableBuffer from '../utils/ResizeableBuffer.js'; +import ResizeableBuffer from "../utils/ResizeableBuffer.js"; // white space characters // https://en.wikipedia.org/wiki/Whitespace_character @@ -11,7 +10,7 @@ const nl = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal const space = 32; const tab = 9; -const init_state = function(options){ +const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -21,9 +20,14 @@ const init_state = function(options){ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: Buffer.isBuffer(options.escape) && Buffer.isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + Buffer.isBuffer(options.escape) && + Buffer.isBuffer(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -41,18 +45,24 @@ const init_state = function(options){ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; -export {init_state}; +export { init_state }; diff --git a/packages/csv-parse/lib/api/normalize_columns_array.js b/packages/csv-parse/lib/api/normalize_columns_array.js index 5d1f5e4b6..c5d5f0002 100644 --- a/packages/csv-parse/lib/api/normalize_columns_array.js +++ b/packages/csv-parse/lib/api/normalize_columns_array.js @@ -1,33 +1,32 @@ +import { CsvError } from "./CsvError.js"; +import { is_object } from "../utils/is_object.js"; -import {CsvError} from './CsvError.js'; -import {is_object} from '../utils/is_object.js'; - -const normalize_columns_array = function(columns){ +const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object(column)) { + if (typeof column.name !== "string") { + throw new CsvError("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else{ - throw new CsvError('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; -export {normalize_columns_array}; +export { normalize_columns_array }; diff --git a/packages/csv-parse/lib/api/normalize_options.js b/packages/csv-parse/lib/api/normalize_options.js index b76369bd9..ecb1eaaa8 100644 --- a/packages/csv-parse/lib/api/normalize_options.js +++ b/packages/csv-parse/lib/api/normalize_options.js @@ -1,455 +1,691 @@ +import { normalize_columns_array } from "./normalize_columns_array.js"; +import { CsvError } from "./CsvError.js"; +import { underscore } from "../utils/underscore.js"; -import {normalize_columns_array} from './normalize_columns_array.js'; -import {CsvError} from './CsvError.js'; -import {underscore} from '../utils/underscore.js'; - -const normalize_options = function(opts){ +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else{ - throw new CsvError('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else{ - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!Buffer.isBuffer(options.comment)){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!Buffer.isBuffer(options.comment)) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); } - if(typeof delimiter === 'string'){ + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!Buffer.isBuffer(delimiter) || delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!Buffer.isBuffer(delimiter) || delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!Buffer.isBuffer(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!Buffer.isBuffer(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else{ - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else{ - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else{ - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else{ - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); - } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); + } + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) { // Great, nothing to do - }else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else{ - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(Buffer.isBuffer(options.objname)){ - if(options.objname.length === 0){ + } else if (Buffer.isBuffer(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null){ + if (options.encoding === null) { // Don't call `toString`, leave objname as a buffer - }else{ + } else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number'){ + } else if (typeof options.objname === "number") { // if(options.objname.length === 0){ // throw new Error(`Invalid Option: objname must be a non empty string`); // } // Great, nothing to do - }else{ - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); - } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + } else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); + } + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else{ // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else{ - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!Buffer.isBuffer(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!Buffer.isBuffer(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || Buffer.isBuffer(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + Buffer.isBuffer(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! Buffer.isBuffer(rd)){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !Buffer.isBuffer(rd)) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); } - if(typeof rd === 'string'){ + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean'){ + if (typeof options.relax_column_count === "boolean") { // Great, nothing to do - }else if(options.relax_column_count === undefined || options.relax_column_count === null){ + } else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else{ - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean'){ + if (typeof options.relax_column_count_less === "boolean") { // Great, nothing to do - }else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + } else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else{ - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean'){ + if (typeof options.relax_column_count_more === "boolean") { // Great, nothing to do - }else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + } else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else{ - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean'){ + if (typeof options.relax_quotes === "boolean") { // Great, nothing to do - }else if(options.relax_quotes === undefined || options.relax_quotes === null){ + } else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else{ - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean'){ + if (typeof options.skip_empty_lines === "boolean") { // Great, nothing to do - }else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + } else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else{ - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean'){ + if (typeof options.skip_records_with_empty_values === "boolean") { // Great, nothing to do - }else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + } else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else{ - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean'){ + if (typeof options.skip_records_with_error === "boolean") { // Great, nothing to do - }else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + } else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else{ - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else{ - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else{ - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else{ - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else{ - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; -export {normalize_options}; +export { normalize_options }; diff --git a/packages/csv-parse/lib/index.js b/packages/csv-parse/lib/index.js index eb03696ee..67eb68dff 100644 --- a/packages/csv-parse/lib/index.js +++ b/packages/csv-parse/lib/index.js @@ -1,4 +1,3 @@ - /* CSV Parse @@ -6,110 +5,128 @@ Please look at the [project documentation](https://csv.js.org/parse/) for additional information. */ -import { Transform } from 'stream'; -import {is_object} from './utils/is_object.js'; -import {transform} from './api/index.js'; -import {CsvError} from './api/CsvError.js'; +import { Transform } from "stream"; +import { is_object } from "./utils/is_object.js"; +import { transform } from "./api/index.js"; +import { CsvError } from "./api/CsvError.js"; class Parser extends Transform { - constructor(opts = {}){ - super({...{readableObjectMode: true}, ...opts, encoding: null}); - this.api = transform({on_skip: (err, chunk) => { - this.emit('skip', err, chunk); - }, ...opts}); + constructor(opts = {}) { + super({ ...{ readableObjectMode: true }, ...opts, encoding: null }); + this.api = transform({ + on_skip: (err, chunk) => { + this.emit("skip", err, chunk); + }, + ...opts, + }); // Backward compatibility this.state = this.api.state; this.options = this.api.options; this.info = this.api.info; } // Implementation of `Transform._transform` - _transform(buf, _, callback){ - if(this.state.stop === true){ + _transform(buf, _, callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(buf, false, (record) => { - this.push(record); - }, () => { - this.push(null); - this.end(); - // Fix #333 and break #410 - // ko: api.stream.iterator.coffee - // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) - // ko: api.stream.finished # aborted (with Readable) - // this.destroy() - // Fix #410 and partially break #333 - // ok: api.stream.iterator.coffee - // ok: api.stream.finished # aborted (with generate()) - // broken: api.stream.finished # aborted (with Readable) - this.on('end', this.destroy); - }); - if(err !== undefined){ + const err = this.api.parse( + buf, + false, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.end(); + // Fix #333 and break #410 + // ko: api.stream.iterator.coffee + // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) + // ko: api.stream.finished # aborted (with Readable) + // this.destroy() + // Fix #410 and partially break #333 + // ok: api.stream.iterator.coffee + // ok: api.stream.finished # aborted (with generate()) + // broken: api.stream.finished # aborted (with Readable) + this.on("end", this.destroy); + }, + ); + if (err !== undefined) { this.state.stop = true; } callback(err); } // Implementation of `Transform._flush` - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(undefined, true, (record) => { - this.push(record); - }, () => { - this.push(null); - this.on('end', this.destroy); - }); + const err = this.api.parse( + undefined, + true, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.on("end", this.destroy); + }, + ); callback(err); } } -const parse = function(){ +const parse = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (typeof argument === 'string' || Buffer.isBuffer(argument))){ + if ( + data === undefined && + (typeof argument === "string" || Buffer.isBuffer(argument)) + ) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else{ - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` - ], options || {}); + } else { + throw new CsvError( + "CSV_INVALID_ARGUMENT", + ["Invalid argument:", `got ${JSON.stringify(argument)} at index ${i}`], + options || {}, + ); } } const parser = new Parser(options); - if(callback){ - const records = options === undefined || options.objname === undefined ? [] : {}; - parser.on('readable', function(){ + if (callback) { + const records = + options === undefined || options.objname === undefined ? [] : {}; + parser.on("readable", function () { let record; - while((record = this.read()) !== null){ - if(options === undefined || options.objname === undefined){ + while ((record = this.read()) !== null) { + if (options === undefined || options.objname === undefined) { records.push(record); - }else{ + } else { records[record[0]] = record[1]; } } }); - parser.on('error', function(err){ + parser.on("error", function (err) { callback(err, undefined, parser.api.__infoDataSet()); }); - parser.on('end', function(){ + parser.on("end", function () { callback(undefined, records, parser.api.__infoDataSet()); }); } - if(data !== undefined){ - const writer = function(){ + if (data !== undefined) { + const writer = function () { parser.write(data); parser.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else{ + } else { setTimeout(writer, 0); } } diff --git a/packages/csv-parse/lib/stream.js b/packages/csv-parse/lib/stream.js index 3aba296b0..8594af1b0 100644 --- a/packages/csv-parse/lib/stream.js +++ b/packages/csv-parse/lib/stream.js @@ -1,27 +1,34 @@ - -import { - TransformStream, -} from 'node:stream/web'; -import {transform} from './api/index.js'; +import { TransformStream } from "node:stream/web"; +import { transform } from "./api/index.js"; const parse = (opts) => { const api = transform(opts); return new TransformStream({ async transform(chunk, controller) { - api.parse(chunk, false, (record) => { - controller.enqueue(record); - }, () => { - controller.close(); - }); + api.parse( + chunk, + false, + (record) => { + controller.enqueue(record); + }, + () => { + controller.close(); + }, + ); + }, + async flush(controller) { + api.parse( + undefined, + true, + (record) => { + controller.enqueue(record); + }, + () => { + controller.close(); + }, + ); }, - async flush(controller){ - api.parse(undefined, true, (record) => { - controller.enqueue(record); - }, () => { - controller.close(); - }); - } }); }; -export {parse}; +export { parse }; diff --git a/packages/csv-parse/lib/sync.js b/packages/csv-parse/lib/sync.js index 4229ea314..5e6b374e5 100644 --- a/packages/csv-parse/lib/sync.js +++ b/packages/csv-parse/lib/sync.js @@ -1,24 +1,22 @@ +import { CsvError, transform } from "./api/index.js"; -import {CsvError, transform} from './api/index.js'; - -const parse = function(data, opts={}){ - if(typeof data === 'string'){ +const parse = function (data, opts = {}) { + if (typeof data === "string") { data = Buffer.from(data); } const records = opts && opts.objname ? {} : []; const parser = transform(opts); const push = (record) => { - if(parser.options.objname === undefined) - records.push(record); - else{ + if (parser.options.objname === undefined) records.push(record); + else { records[record[0]] = record[1]; } }; const close = () => {}; const err1 = parser.parse(data, false, push, close); - if(err1 !== undefined) throw err1; + if (err1 !== undefined) throw err1; const err2 = parser.parse(undefined, true, push, close); - if(err2 !== undefined) throw err2; + if (err2 !== undefined) throw err2; return records; }; diff --git a/packages/csv-parse/lib/utils/ResizeableBuffer.js b/packages/csv-parse/lib/utils/ResizeableBuffer.js index 4979e9199..82396e981 100644 --- a/packages/csv-parse/lib/utils/ResizeableBuffer.js +++ b/packages/csv-parse/lib/utils/ResizeableBuffer.js @@ -1,17 +1,16 @@ - -class ResizeableBuffer{ - constructor(size=100){ +class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(Buffer.isBuffer(val)){ + prepend(val) { + if (Buffer.isBuffer(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -19,44 +18,44 @@ class ResizeableBuffer{ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else{ + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else{ + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } diff --git a/packages/csv-parse/lib/utils/is_object.js b/packages/csv-parse/lib/utils/is_object.js index 4f958460c..d8b70e248 100644 --- a/packages/csv-parse/lib/utils/is_object.js +++ b/packages/csv-parse/lib/utils/is_object.js @@ -1,6 +1,5 @@ - -const is_object = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; -export {is_object}; +export { is_object }; diff --git a/packages/csv-parse/lib/utils/underscore.js b/packages/csv-parse/lib/utils/underscore.js index 453816be6..6281e0096 100644 --- a/packages/csv-parse/lib/utils/underscore.js +++ b/packages/csv-parse/lib/utils/underscore.js @@ -1,8 +1,7 @@ - -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -export {underscore}; +export { underscore }; diff --git a/packages/csv-parse/package.json b/packages/csv-parse/package.json index 87ffc7067..10707fa3c 100644 --- a/packages/csv-parse/package.json +++ b/packages/csv-parse/package.json @@ -62,14 +62,18 @@ } }, "devDependencies": { - "coffeelint": "^2.1.0", + "@eslint/js": "^9.9.1", + "@rollup/plugin-node-resolve": "^15.2.3", "@types/mocha": "^10.0.7", "@types/node": "^22.5.0", "coffeescript": "^2.7.0", "csv-generate": "^4.4.1", - "eslint": "^8.47.0", "csv-spectrum": "^2.0.0", "each": "^2.7.0", + "eslint": "^9.9.1", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-mocha": "^10.5.0", + "eslint-plugin-prettier": "^5.2.1", "mocha": "^10.7.3", "pad": "^3.2.0", "prettier": "^3.3.3", @@ -109,11 +113,8 @@ "build:rollup": "npx rollup -c", "build:ts": "cp lib/index.d.ts dist/cjs/index.d.cts && cp lib/sync.d.ts dist/cjs/sync.d.cts && cp lib/*.ts dist/esm", "postbuild:ts": "find dist/cjs -name '*.d.cts' -exec sh -c \"sed -i \"s/\\.js'/\\.cjs'/g\" {} || sed -i '' \"s/\\.js'/\\.cjs'/g\" {}\" \\;", - "lint": "npm run lint:lib && npm run lint:samples && npm run lint:test", - "postlint": "tsc --noEmit true", - "lint:lib": "eslint --fix lib/*.js", - "lint:samples": "eslint --fix samples/*.js", - "lint:test": "coffeelint --fix test/*.coffee", + "lint:check": "eslint && tsc --noEmit true", + "lint:fix": "eslint --fix && tsc --noEmit true", "preversion": "npm run build && git add dist", "pretest": "npm run build", "test": "mocha 'test/**/*.{coffee,ts}'", diff --git a/packages/csv-parse/rollup.config.js b/packages/csv-parse/rollup.config.js index 88884a159..e978b577c 100644 --- a/packages/csv-parse/rollup.config.js +++ b/packages/csv-parse/rollup.config.js @@ -1,82 +1,102 @@ +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import globals from "rollup-plugin-node-globals"; +import builtins from "rollup-plugin-node-builtins"; +// import eslint from "@rollup/plugin-eslint"; -import { nodeResolve } from '@rollup/plugin-node-resolve'; -import globals from 'rollup-plugin-node-globals'; -import builtins from 'rollup-plugin-node-builtins'; -import eslint from '@rollup/plugin-eslint'; - -export default [{ - onwarn: function(warning, rollupWarn) { - // Not much we can do, Node.js `readable-stream/readable.js` and - // `readable-stream/duplex.js` from `rollup-plugin-node-builtins` raise this - // issue. - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - rollupWarn(warning); - }, - input: 'lib/index.js', - output: [ - { - file: `dist/esm/index.js`, - format: 'esm' - }, - { - file: `dist/iife/index.js`, - format: 'iife', - name: 'csv_parse' +export default [ + { + onwarn: function (warning, rollupWarn) { + // Not much we can do, Node.js `readable-stream/readable.js` and + // `readable-stream/duplex.js` from `rollup-plugin-node-builtins` raise this + // issue. + if (warning.code === "CIRCULAR_DEPENDENCY") return; + rollupWarn(warning); }, - { - file: `dist/umd/index.js`, - format: 'umd', - name: 'csv_parse' - }, - ], - plugins: [eslint({ - fix: true, - }), globals(), builtins(), nodeResolve()], -}, { - input: 'lib/index.js', - output: [ - { - file: `dist/cjs/index.cjs`, - format: 'cjs' - }, - ], - plugins: [eslint({ - fix: true, - }), nodeResolve()], -}, { - onwarn: function(warning, rollupWarn) { - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - rollupWarn(warning); + input: "lib/index.js", + output: [ + { + file: `dist/esm/index.js`, + format: "esm", + }, + { + file: `dist/iife/index.js`, + format: "iife", + name: "csv_parse", + }, + { + file: `dist/umd/index.js`, + format: "umd", + name: "csv_parse", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + globals(), + builtins(), + nodeResolve(), + ], }, - input: 'lib/sync.js', - output: [ - { - file: `dist/esm/sync.js`, - format: 'esm' - }, - { - file: `dist/iife/sync.js`, - format: 'iife', - name: 'csv_parse_sync' - }, - { - file: `dist/umd/sync.js`, - format: 'umd', - name: 'csv_parse_sync' - }, - ], - plugins: [eslint({ - fix: true, - }), globals(), builtins(), nodeResolve()], -}, { - input: 'lib/sync.js', - output: [ - { - file: `dist/cjs/sync.cjs`, - format: 'cjs' + { + input: "lib/index.js", + output: [ + { + file: `dist/cjs/index.cjs`, + format: "cjs", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + nodeResolve(), + ], + }, + { + onwarn: function (warning, rollupWarn) { + if (warning.code === "CIRCULAR_DEPENDENCY") return; + rollupWarn(warning); }, - ], - plugins: [eslint({ - fix: true, - }), nodeResolve()], -}]; + input: "lib/sync.js", + output: [ + { + file: `dist/esm/sync.js`, + format: "esm", + }, + { + file: `dist/iife/sync.js`, + format: "iife", + name: "csv_parse_sync", + }, + { + file: `dist/umd/sync.js`, + format: "umd", + name: "csv_parse_sync", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + globals(), + builtins(), + nodeResolve(), + ], + }, + { + input: "lib/sync.js", + output: [ + { + file: `dist/cjs/sync.cjs`, + format: "cjs", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + nodeResolve(), + ], + }, +]; diff --git a/packages/csv-parse/samples/api.callback.js b/packages/csv-parse/samples/api.callback.js index 18fed7abf..30b61d74c 100644 --- a/packages/csv-parse/samples/api.callback.js +++ b/packages/csv-parse/samples/api.callback.js @@ -1,13 +1,16 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse'; +import assert from "node:assert"; +import { parse } from "csv-parse"; const input = '#Welcome\n"1","2","3","4"\n"a","b","c","d"'; -parse(input, { - comment: '#' -}, function(err, records){ - assert.deepStrictEqual( - records, - [ [ '1', '2', '3', '4' ], [ 'a', 'b', 'c', 'd' ] ] - ); -}); +parse( + input, + { + comment: "#", + }, + function (err, records) { + assert.deepStrictEqual(records, [ + ["1", "2", "3", "4"], + ["a", "b", "c", "d"], + ]); + }, +); diff --git a/packages/csv-parse/samples/api.info.callback.js b/packages/csv-parse/samples/api.info.callback.js index dd8ce98e3..b839b3094 100644 --- a/packages/csv-parse/samples/api.info.callback.js +++ b/packages/csv-parse/samples/api.info.callback.js @@ -1,11 +1,9 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse('1,2,3\na,b,c', (err, data, {lines, records}) => { +parse("1,2,3\na,b,c", (err, data, { lines, records }) => { assert.equal( - `There are ${lines} lines with ${records} records.` - , - 'There are 2 lines with 2 records.' + `There are ${lines} lines with ${records} records.`, + "There are 2 lines with 2 records.", ); }); diff --git a/packages/csv-parse/samples/api.info.internal.js b/packages/csv-parse/samples/api.info.internal.js index 5bba736c6..9dd9f3b3c 100644 --- a/packages/csv-parse/samples/api.info.internal.js +++ b/packages/csv-parse/samples/api.info.internal.js @@ -1,26 +1,25 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -const parser = parse('1,2,3\na,b,c'); +const parser = parse("1,2,3\na,b,c"); // Report information for every record -parser.on('readable', () => { +parser.on("readable", () => { while (parser.read() !== null) { - const {lines, records} = parser.info; + const { lines, records } = parser.info; // Note, `lines` might equal `2` even for the first record because // the parser already processed the second line at the time we get here. assert( - /Current state is \d lines and \d records\./ - .test(`Current state is ${lines} lines and ${records} records.`) + /Current state is \d lines and \d records\./.test( + `Current state is ${lines} lines and ${records} records.`, + ), ); } }); // Report information when the process is finished -parser.on('end', () => { +parser.on("end", () => { const { lines, records } = parser.info; assert.equal( - `There are ${lines} lines with ${records} records.` - , - 'There are 2 lines with 2 records.' + `There are ${lines} lines with ${records} records.`, + "There are 2 lines with 2 records.", ); }); diff --git a/packages/csv-parse/samples/api.stream.js b/packages/csv-parse/samples/api.stream.js index 79a1e957e..1493bd2de 100644 --- a/packages/csv-parse/samples/api.stream.js +++ b/packages/csv-parse/samples/api.stream.js @@ -1,35 +1,31 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse'; +import assert from "node:assert"; +import { parse } from "csv-parse"; const records = []; // Initialize the parser const parser = parse({ - delimiter: ':' + delimiter: ":", }); // Use the readable stream api to consume records -parser.on('readable', function(){ +parser.on("readable", function () { let record; while ((record = parser.read()) !== null) { records.push(record); } }); // Catch any error -parser.on('error', function(err){ +parser.on("error", function (err) { console.error(err.message); }); // Test that the parsed records matched the expected records -parser.on('end', function(){ - assert.deepStrictEqual( - records, - [ - [ 'root','x','0','0','root','/root','/bin/bash' ], - [ 'someone','x','1022','1022','','/home/someone','/bin/bash' ] - ] - ); +parser.on("end", function () { + assert.deepStrictEqual(records, [ + ["root", "x", "0", "0", "root", "/root", "/bin/bash"], + ["someone", "x", "1022", "1022", "", "/home/someone", "/bin/bash"], + ]); }); // Write data to the stream -parser.write('root:x:0:0:root:/root:/bin/bash\n'); -parser.write('someone:x:1022:1022::/home/someone:/bin/bash\n'); +parser.write("root:x:0:0:root:/root:/bin/bash\n"); +parser.write("someone:x:1022:1022::/home/someone:/bin/bash\n"); // Close the readable stream parser.end(); diff --git a/packages/csv-parse/samples/api.sync.js b/packages/csv-parse/samples/api.sync.js index 423562729..229c329e6 100644 --- a/packages/csv-parse/samples/api.sync.js +++ b/packages/csv-parse/samples/api.sync.js @@ -1,6 +1,5 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; const input = ` "key_1","key_2" @@ -8,9 +7,6 @@ const input = ` `; const records = parse(input, { columns: true, - skip_empty_lines: true + skip_empty_lines: true, }); -assert.deepStrictEqual( - records, - [{ key_1: 'value 1', key_2: 'value 2' }] -); +assert.deepStrictEqual(records, [{ key_1: "value 1", key_2: "value 2" }]); diff --git a/packages/csv-parse/samples/async.iterator.js b/packages/csv-parse/samples/async.iterator.js index 98998627b..9a002e9d9 100644 --- a/packages/csv-parse/samples/async.iterator.js +++ b/packages/csv-parse/samples/async.iterator.js @@ -1,29 +1,26 @@ - -import assert from 'node:assert'; -import { generate } from 'csv-generate'; -import { parse } from 'csv-parse'; +import assert from "node:assert"; +import { generate } from "csv-generate"; +import { parse } from "csv-parse"; (async () => { // Initialise the parser by generating random records const parser = generate({ high_water_mark: 64 * 64, - length: 100 - }).pipe( - parse() - ); + length: 100, + }).pipe(parse()); // Intialise count let count = 0; // Report start - process.stdout.write('start\n'); + process.stdout.write("start\n"); // Iterate through each records for await (const record of parser) { // Report current line - process.stdout.write(`${count++} ${record.join(',')}\n`); + process.stdout.write(`${count++} ${record.join(",")}\n`); // Fake asynchronous operation await new Promise((resolve) => setTimeout(resolve, 100)); } // Report end - process.stdout.write('...done\n'); + process.stdout.write("...done\n"); // Validation assert.strictEqual(count, 100); })(); diff --git a/packages/csv-parse/samples/columns-discovery.js b/packages/csv-parse/samples/columns-discovery.js index da5b095ea..30ad6e14e 100644 --- a/packages/csv-parse/samples/columns-discovery.js +++ b/packages/csv-parse/samples/columns-discovery.js @@ -1,12 +1,11 @@ +import fs from "node:fs"; +import { parse } from "csv-parse"; -import fs from 'node:fs'; -import { parse } from 'csv-parse'; - -const __dirname = new URL('.', import.meta.url).pathname; +const __dirname = new URL(".", import.meta.url).pathname; // Using the first line of the CSV data to discover the column names -const rs = fs.createReadStream(__dirname+'/columns-discovery.in'); -const parser = parse({columns: true}, function(err, data){ +const rs = fs.createReadStream(__dirname + "/columns-discovery.in"); +const parser = parse({ columns: true }, function (err, data) { console.info(data); }); rs.pipe(parser); diff --git a/packages/csv-parse/samples/comment.js b/packages/csv-parse/samples/comment.js index b07a5301c..695b49313 100644 --- a/packages/csv-parse/samples/comment.js +++ b/packages/csv-parse/samples/comment.js @@ -1,14 +1,13 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse'; +import assert from "node:assert"; +import { parse } from "csv-parse"; parse( '#Welcome\n"1","2","3","4"\n"a","b","c","d"', - {comment: '#'}, - function(err, data){ - assert.deepStrictEqual( - data, - [ [ '1', '2', '3', '4' ], [ 'a', 'b', 'c', 'd' ] ] - ); - } + { comment: "#" }, + function (err, data) { + assert.deepStrictEqual(data, [ + ["1", "2", "3", "4"], + ["a", "b", "c", "d"], + ]); + }, ); diff --git a/packages/csv-parse/samples/fs_read.js b/packages/csv-parse/samples/fs_read.js index af2fd1774..1e093d48c 100644 --- a/packages/csv-parse/samples/fs_read.js +++ b/packages/csv-parse/samples/fs_read.js @@ -1,11 +1,10 @@ +import fs from "node:fs"; +import { parse } from "csv-parse"; -import fs from 'node:fs'; -import { parse } from 'csv-parse'; +const __dirname = new URL(".", import.meta.url).pathname; -const __dirname = new URL('.', import.meta.url).pathname; - -const parser = parse({delimiter: ';'}, function(err, data){ +const parser = parse({ delimiter: ";" }, function (err, data) { console.info(data); }); -fs.createReadStream(__dirname+'/fs_read.csv').pipe(parser); +fs.createReadStream(__dirname + "/fs_read.csv").pipe(parser); diff --git a/packages/csv-parse/samples/mixed.input_stream.js b/packages/csv-parse/samples/mixed.input_stream.js index f70ba94b1..365ae6349 100644 --- a/packages/csv-parse/samples/mixed.input_stream.js +++ b/packages/csv-parse/samples/mixed.input_stream.js @@ -1,21 +1,20 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse'; +import assert from "node:assert"; +import { parse } from "csv-parse"; // Create the parser -const parser = parse({ - delimiter: ':' -}, function(err, records){ - assert.deepStrictEqual( - records, - [ - [ 'root','x','0','0','root','/root','/bin/bash' ], - [ 'someone','x','1022','1022','','/home/someone','/bin/bash' ] - ] - ); -}); +const parser = parse( + { + delimiter: ":", + }, + function (err, records) { + assert.deepStrictEqual(records, [ + ["root", "x", "0", "0", "root", "/root", "/bin/bash"], + ["someone", "x", "1022", "1022", "", "/home/someone", "/bin/bash"], + ]); + }, +); // Write data to the stream -parser.write('root:x:0:0:root:/root:/bin/bash\n'); -parser.write('someone:x:1022:1022::/home/someone:/bin/bash\n'); +parser.write("root:x:0:0:root:/root:/bin/bash\n"); +parser.write("someone:x:1022:1022::/home/someone:/bin/bash\n"); // Close the readable stream parser.end(); diff --git a/packages/csv-parse/samples/mixed.output_stream.js b/packages/csv-parse/samples/mixed.output_stream.js index 62369f031..b9dd10d8f 100644 --- a/packages/csv-parse/samples/mixed.output_stream.js +++ b/packages/csv-parse/samples/mixed.output_stream.js @@ -1,28 +1,28 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse'; +import assert from "node:assert"; +import { parse } from "csv-parse"; const records = []; -parse(` +parse( + ` "1","2","3" "a","b","c" -`, { - trim: true, - skip_empty_lines: true -}) -// Use the readable stream api - .on('readable', function(){ - let record; while ((record = this.read()) !== null) { +`, + { + trim: true, + skip_empty_lines: true, + }, +) + // Use the readable stream api + .on("readable", function () { + let record; + while ((record = this.read()) !== null) { records.push(record); } }) -// When we are done, test that the parsed records matched what expected - .on('end', function(){ - assert.deepStrictEqual( - records, - [ - [ '1','2','3' ], - [ 'a','b','c' ] - ] - ); + // When we are done, test that the parsed records matched what expected + .on("end", function () { + assert.deepStrictEqual(records, [ + ["1", "2", "3"], + ["a", "b", "c"], + ]); }); diff --git a/packages/csv-parse/samples/option.bom.hidden.js b/packages/csv-parse/samples/option.bom.hidden.js index d77f75afd..ef5aadd32 100644 --- a/packages/csv-parse/samples/option.bom.hidden.js +++ b/packages/csv-parse/samples/option.bom.hidden.js @@ -1,13 +1,12 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; const data = "\ufeffkey\nvalue"; const records = parse(data, { bom: false, - columns: true + columns: true, }); // It seems that the output is perfectly fine assert.equal(JSON.stringify(records[0]), '{"key":"value"}'); // However, the first property include the BOM bytes -assert.equal(Object.keys(records[0])[0], '\ufeffkey'); +assert.equal(Object.keys(records[0])[0], "\ufeffkey"); diff --git a/packages/csv-parse/samples/option.bom.js b/packages/csv-parse/samples/option.bom.js index 2b9809c8f..7d7114b49 100644 --- a/packages/csv-parse/samples/option.bom.js +++ b/packages/csv-parse/samples/option.bom.js @@ -1,11 +1,8 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const data = '\ufeffa,b,c\n'; +const data = "\ufeffa,b,c\n"; const records = parse(data, { - bom: true + bom: true, }); -assert.deepStrictEqual(records, [ - [ 'a', 'b', 'c' ] -]); +assert.deepStrictEqual(records, [["a", "b", "c"]]); diff --git a/packages/csv-parse/samples/option.cast.context.js b/packages/csv-parse/samples/option.cast.context.js index 8270f0c85..cae9ef6a9 100644 --- a/packages/csv-parse/samples/option.cast.context.js +++ b/packages/csv-parse/samples/option.cast.context.js @@ -1,36 +1,61 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; const data = ` 2000-01-01,date1 2050-11-27,date2 `.trim(); const records = parse(data, { - // The cast option exect a function which + // The cast option exect a function which // is called with two arguments, // the parsed value and a context object - cast: function(value, context){ + cast: function (value, context) { // You can return any value - if(context.index === 0){ + if (context.index === 0) { // Such as a string return `${value}T05:00:00.000Z`; - }else{ + } else { // Or the `context` object literal return context; } }, - trim: true + trim: true, }); assert.deepStrictEqual(records, [ - [ '2000-01-01T05:00:00.000Z', { - bytes: 16, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, - lines: 1, records: 0, columns: false, error: undefined, header: false, - index: 1, column: 1, quoting: false, raw: undefined - } ], - [ '2050-11-27T05:00:00.000Z', { - bytes: 35, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, - lines: 2, records: 1, columns: false, error: undefined, header: false, - index: 1, column: 1, quoting: false, raw: undefined - } ] + [ + "2000-01-01T05:00:00.000Z", + { + bytes: 16, + comment_lines: 0, + empty_lines: 0, + invalid_field_length: 0, + lines: 1, + records: 0, + columns: false, + error: undefined, + header: false, + index: 1, + column: 1, + quoting: false, + raw: undefined, + }, + ], + [ + "2050-11-27T05:00:00.000Z", + { + bytes: 35, + comment_lines: 0, + empty_lines: 0, + invalid_field_length: 0, + lines: 2, + records: 1, + columns: false, + error: undefined, + header: false, + index: 1, + column: 1, + quoting: false, + raw: undefined, + }, + ], ]); diff --git a/packages/csv-parse/samples/option.cast.header.column.fn.js b/packages/csv-parse/samples/option.cast.header.column.fn.js index 7a1361000..1426f5e84 100644 --- a/packages/csv-parse/samples/option.cast.header.column.fn.js +++ b/packages/csv-parse/samples/option.cast.header.column.fn.js @@ -1,20 +1,20 @@ - -import assert from 'node:assert'; -import {parse} from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; assert.deepEqual( - parse('a,b,c\n1,2,3\n4,5,6', { + parse("a,b,c\n1,2,3\n4,5,6", { cast: (value, context) => { - if(context.header) return value; - if (context.column === 'B') return Number(value); + if (context.header) return value; + if (context.column === "B") return Number(value); return String(value); }, columns: (header) => { return header.map((label) => label.toUpperCase()); }, trim: true, - }) - , [ - { A: '1', B: 2, C: '3' }, - { A: '4', B: 5, C: '6' } - ]); + }), + [ + { A: "1", B: 2, C: "3" }, + { A: "4", B: 5, C: "6" }, + ], +); diff --git a/packages/csv-parse/samples/option.cast.header.columns.true.js b/packages/csv-parse/samples/option.cast.header.columns.true.js index 186396792..c7de0f764 100644 --- a/packages/csv-parse/samples/option.cast.header.columns.true.js +++ b/packages/csv-parse/samples/option.cast.header.columns.true.js @@ -1,18 +1,18 @@ - -import assert from 'node:assert'; -import {parse} from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; assert.deepEqual( - parse('a,b,c\n1,2,3\n4,5,6', { + parse("a,b,c\n1,2,3\n4,5,6", { cast: (value, context) => { - if(context.header) return value.toUpperCase(); - if (context.column === 'B') return Number(value); + if (context.header) return value.toUpperCase(); + if (context.column === "B") return Number(value); return String(value); }, columns: true, trim: true, - }) - , [ - { A: '1', B: 2, C: '3' }, - { A: '4', B: 5, C: '6' } - ]); + }), + [ + { A: "1", B: 2, C: "3" }, + { A: "4", B: 5, C: "6" }, + ], +); diff --git a/packages/csv-parse/samples/option.cast.js b/packages/csv-parse/samples/option.cast.js index 7a1779971..482efb341 100644 --- a/packages/csv-parse/samples/option.cast.js +++ b/packages/csv-parse/samples/option.cast.js @@ -1,4 +1,3 @@ - import assert from "node:assert"; import { parse } from "csv-parse/sync"; @@ -26,6 +25,6 @@ const records = parse(data, { trim: true, }); assert.deepStrictEqual(records, [ - [ "1", 2, "Value is 3" ], - [ "4", 5, "Value is 6" ], + ["1", 2, "Value is 3"], + ["4", 5, "Value is 6"], ]); diff --git a/packages/csv-parse/samples/option.cast_date.js b/packages/csv-parse/samples/option.cast_date.js index a134513a1..e3b282f2f 100644 --- a/packages/csv-parse/samples/option.cast_date.js +++ b/packages/csv-parse/samples/option.cast_date.js @@ -1,6 +1,5 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; const data = ` 2000-01-01,date1 @@ -8,9 +7,9 @@ const data = ` `.trim(); const records = parse(data, { cast: true, - cast_date: true + cast_date: true, }); assert.deepStrictEqual(records, [ - [ new Date('2000-01-01T00:00:00.000Z'), 'date1' ], - [ new Date('2020-01-01T00:00:00.000Z'), 'date2' ] + [new Date("2000-01-01T00:00:00.000Z"), "date1"], + [new Date("2020-01-01T00:00:00.000Z"), "date2"], ]); diff --git a/packages/csv-parse/samples/option.columns.array.js b/packages/csv-parse/samples/option.columns.array.js index daec1bdec..06ddb71be 100644 --- a/packages/csv-parse/samples/option.columns.array.js +++ b/packages/csv-parse/samples/option.columns.array.js @@ -1,16 +1,19 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` "value 1","value 2" -`.trim(), { - columns: ['key_1', 'key_2'] -}, function(err, records){ - assert.deepStrictEqual( - records, [{ - key_1: 'value 1', - key_2: 'value 2' - }] - ); -}); +`.trim(), + { + columns: ["key_1", "key_2"], + }, + function (err, records) { + assert.deepStrictEqual(records, [ + { + key_1: "value 1", + key_2: "value 2", + }, + ]); + }, +); diff --git a/packages/csv-parse/samples/option.columns.function.js b/packages/csv-parse/samples/option.columns.function.js index 7ff76d50a..a6fa7a873 100644 --- a/packages/csv-parse/samples/option.columns.function.js +++ b/packages/csv-parse/samples/option.columns.function.js @@ -1,18 +1,20 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` "key_1","key_2" "value 1","value 2" -`.trim(), { - columns: header => - header.map(column => column.toUpperCase()) -}, function(err, records){ - assert.deepStrictEqual( - records, [{ - KEY_1: 'value 1', - KEY_2: 'value 2' - }] - ); -}); +`.trim(), + { + columns: (header) => header.map((column) => column.toUpperCase()), + }, + function (err, records) { + assert.deepStrictEqual(records, [ + { + KEY_1: "value 1", + KEY_2: "value 2", + }, + ]); + }, +); diff --git a/packages/csv-parse/samples/option.columns.true.js b/packages/csv-parse/samples/option.columns.true.js index cb401a182..b244d6b06 100644 --- a/packages/csv-parse/samples/option.columns.true.js +++ b/packages/csv-parse/samples/option.columns.true.js @@ -1,17 +1,20 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` "key_1","key_2" "value 1","value 2" -`.trim(), { - columns: true -}, function(err, records){ - assert.deepStrictEqual( - records, [{ - key_1: 'value 1', - key_2: 'value 2' - }] - ); -}); +`.trim(), + { + columns: true, + }, + function (err, records) { + assert.deepStrictEqual(records, [ + { + key_1: "value 1", + key_2: "value 2", + }, + ]); + }, +); diff --git a/packages/csv-parse/samples/option.comment.js b/packages/csv-parse/samples/option.comment.js index 42b237963..20a2f6319 100644 --- a/packages/csv-parse/samples/option.comment.js +++ b/packages/csv-parse/samples/option.comment.js @@ -1,6 +1,5 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; const data = ` # At the beginning of a record @@ -8,9 +7,6 @@ const data = ` "world"# At the end of a record `.trim(); const records = parse(data, { - comment: "#" + comment: "#", }); -assert.deepStrictEqual(records, [ - [ 'hello' ], - [ 'world' ] -]); +assert.deepStrictEqual(records, [["hello"], ["world"]]); diff --git a/packages/csv-parse/samples/option.comment_no_infix.js b/packages/csv-parse/samples/option.comment_no_infix.js index a6129f061..24ce92bef 100644 --- a/packages/csv-parse/samples/option.comment_no_infix.js +++ b/packages/csv-parse/samples/option.comment_no_infix.js @@ -1,15 +1,15 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const output = parse(` +const output = parse( + ` # Illustrate the usage of comment_no_infix a,b#,c -`.trim(), { - comment: '#', - comment_no_infix: true -}); +`.trim(), + { + comment: "#", + comment_no_infix: true, + }, +); -assert.deepStrictEqual(output, [ - ['a', 'b#', 'c'] -]); +assert.deepStrictEqual(output, [["a", "b#", "c"]]); diff --git a/packages/csv-parse/samples/option.delimiter.array.js b/packages/csv-parse/samples/option.delimiter.array.js index 62d7fb836..d0bb0c4aa 100644 --- a/packages/csv-parse/samples/option.delimiter.array.js +++ b/packages/csv-parse/samples/option.delimiter.array.js @@ -1,6 +1,5 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; const input = `color name::red::green::blue Cyan \t "0" :: 255 :: 255 @@ -8,19 +7,25 @@ Yellow \t "255" :: "255" ::"0" Hot Pink \t "255" :: 105 :: "180"`; const output = parse(input, { - delimiter: ['::','\t'], + delimiter: ["::", "\t"], trim: true, columns: true, -}).map((rec) => { - let indent = ''; - return Object.entries(rec).map(([key, value]) => { - const row = `${indent}${key}: <${value}>`; - indent = (indent.length === 0 ? ' ' : indent); - return row; - }).join('\n'); -}).join('\n'); +}) + .map((rec) => { + let indent = ""; + return Object.entries(rec) + .map(([key, value]) => { + const row = `${indent}${key}: <${value}>`; + indent = indent.length === 0 ? " " : indent; + return row; + }) + .join("\n"); + }) + .join("\n"); -assert.equal(output, ` +assert.equal( + output, + ` color name: red: <0> green: <255> @@ -33,4 +38,5 @@ color name: red: <255> green: <105> blue: <180> -`.trim()); +`.trim(), +); diff --git a/packages/csv-parse/samples/option.delimiter.js b/packages/csv-parse/samples/option.delimiter.js index 03cec4562..7c3d2a648 100644 --- a/packages/csv-parse/samples/option.delimiter.js +++ b/packages/csv-parse/samples/option.delimiter.js @@ -1,12 +1,9 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const data = 'a key => a value'; +const data = "a key => a value"; const records = parse(data, { - delimiter: '=>', - trim: true + delimiter: "=>", + trim: true, }); -assert.deepStrictEqual(records, [ - [ 'a key', 'a value' ] -]); +assert.deepStrictEqual(records, [["a key", "a value"]]); diff --git a/packages/csv-parse/samples/option.encoding.buffer.js b/packages/csv-parse/samples/option.encoding.buffer.js index 8af217a7b..cc964ef81 100644 --- a/packages/csv-parse/samples/option.encoding.buffer.js +++ b/packages/csv-parse/samples/option.encoding.buffer.js @@ -1,12 +1,11 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; const data = Buffer.from(`a,b\n1,2`); const records = parse(data, { - encoding: null + encoding: null, }); assert.deepEqual(records, [ - [ Buffer.from('a'), Buffer.from('b') ], - [ Buffer.from('1'), Buffer.from('2') ] + [Buffer.from("a"), Buffer.from("b")], + [Buffer.from("1"), Buffer.from("2")], ]); diff --git a/packages/csv-parse/samples/option.encoding.detection.js b/packages/csv-parse/samples/option.encoding.detection.js index 7155b7682..6164b149f 100644 --- a/packages/csv-parse/samples/option.encoding.detection.js +++ b/packages/csv-parse/samples/option.encoding.detection.js @@ -1,12 +1,11 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const data = Buffer.from(`\uFEFFa,b,c\n1,2,3`, 'utf16le'); +const data = Buffer.from(`\uFEFFa,b,c\n1,2,3`, "utf16le"); const records = parse(data, { - bom: true + bom: true, }); assert.deepStrictEqual(records, [ - [ 'a', 'b', 'c' ], - [ '1', '2', '3' ] + ["a", "b", "c"], + ["1", "2", "3"], ]); diff --git a/packages/csv-parse/samples/option.encoding.options.js b/packages/csv-parse/samples/option.encoding.options.js index 62cc77388..c4f56bead 100644 --- a/packages/csv-parse/samples/option.encoding.options.js +++ b/packages/csv-parse/samples/option.encoding.options.js @@ -1,13 +1,12 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const data = Buffer.from(`a:b\n1:2`, 'utf16le'); +const data = Buffer.from(`a:b\n1:2`, "utf16le"); const records = parse(data, { - encoding: 'utf16le', - delimiter: Buffer.from(':', 'utf16le') + encoding: "utf16le", + delimiter: Buffer.from(":", "utf16le"), }); assert.deepStrictEqual(records, [ - ['a', 'b'], - ['1', '2'] + ["a", "b"], + ["1", "2"], ]); diff --git a/packages/csv-parse/samples/option.escape.custom.js b/packages/csv-parse/samples/option.escape.custom.js index c23780b7a..058155449 100644 --- a/packages/csv-parse/samples/option.escape.custom.js +++ b/packages/csv-parse/samples/option.escape.custom.js @@ -1,9 +1,6 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; const data = `a,"b\\"c",d`; -const records = parse(data, { escape: '\\' }); -assert.deepStrictEqual(records, [ - [ 'a', 'b"c', 'd' ] -]); +const records = parse(data, { escape: "\\" }); +assert.deepStrictEqual(records, [["a", 'b"c', "d"]]); diff --git a/packages/csv-parse/samples/option.escape.default.js b/packages/csv-parse/samples/option.escape.default.js index b92dc9568..5967bfb3b 100644 --- a/packages/csv-parse/samples/option.escape.default.js +++ b/packages/csv-parse/samples/option.escape.default.js @@ -1,9 +1,6 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; const data = `a,"b""c",d`; const records = parse(data); -assert.deepStrictEqual(records, [ - [ 'a', 'b"c', 'd' ] -]); +assert.deepStrictEqual(records, [["a", 'b"c', "d"]]); diff --git a/packages/csv-parse/samples/option.from.js b/packages/csv-parse/samples/option.from.js index 4de5584cb..0da49347a 100644 --- a/packages/csv-parse/samples/option.from.js +++ b/packages/csv-parse/samples/option.from.js @@ -1,23 +1,27 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` a,b 1,2 3,4 5,6 -`.trim(), { - columns: true, - from: 2 -}, function(err, records){ - assert.deepStrictEqual( - records, [{ - a: '3', - b: '4' - }, { - a: '5', - b: '6' - }] - ); -}); +`.trim(), + { + columns: true, + from: 2, + }, + function (err, records) { + assert.deepStrictEqual(records, [ + { + a: "3", + b: "4", + }, + { + a: "5", + b: "6", + }, + ]); + }, +); diff --git a/packages/csv-parse/samples/option.from_line.js b/packages/csv-parse/samples/option.from_line.js index f9e1eb567..767c5ef5a 100644 --- a/packages/csv-parse/samples/option.from_line.js +++ b/packages/csv-parse/samples/option.from_line.js @@ -1,19 +1,22 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` x,x a,b 1,2 -`.trim(), { - columns: true, - from_line: 2 -}, function(err, records){ - assert.deepStrictEqual( - records, [{ - a: '1', - b: '2' - }] - ); -}); +`.trim(), + { + columns: true, + from_line: 2, + }, + function (err, records) { + assert.deepStrictEqual(records, [ + { + a: "1", + b: "2", + }, + ]); + }, +); diff --git a/packages/csv-parse/samples/option.group_columns_by_name.js b/packages/csv-parse/samples/option.group_columns_by_name.js index 18c29f3e8..2eb513c46 100644 --- a/packages/csv-parse/samples/option.group_columns_by_name.js +++ b/packages/csv-parse/samples/option.group_columns_by_name.js @@ -1,22 +1,26 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` friend,username,friend athos,porthos,aramis porthos,d_artagnan,athos -`.trim(), { - columns: true, - group_columns_by_name: true -}, function(err, records){ - assert.deepStrictEqual( - records, [{ - username: 'porthos', - friend: ['athos', 'aramis'] - }, { - username: 'd_artagnan', - friend: ['porthos', 'athos'] - }] - ); -}); +`.trim(), + { + columns: true, + group_columns_by_name: true, + }, + function (err, records) { + assert.deepStrictEqual(records, [ + { + username: "porthos", + friend: ["athos", "aramis"], + }, + { + username: "d_artagnan", + friend: ["porthos", "athos"], + }, + ]); + }, +); diff --git a/packages/csv-parse/samples/option.ignore_last_delimiters.js b/packages/csv-parse/samples/option.ignore_last_delimiters.js index 8e6fb380c..8aa3ffc38 100644 --- a/packages/csv-parse/samples/option.ignore_last_delimiters.js +++ b/packages/csv-parse/samples/option.ignore_last_delimiters.js @@ -1,26 +1,35 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` format;description CSV;CSV delimited text file that uses a comma, by default, to separate values. SSA;SSA is a subtitle file format that allows for more advanced subtitles than the conventional SRT and similar formats. ASS;Advanced SubStation Alpha (ASS), technically SSA v4+, is a script for more advanced subtitles than SSA. -`.trim(), { - delimiter: ";", - columns: true, - ignore_last_delimiters: 10 -}, function(err, records){ - assert.deepStrictEqual(records, [{ - format: 'CSV', - description: 'CSV delimited text file that uses a comma, by default, to separate values.' - },{ - format: 'SSA', - description: 'SSA is a subtitle file format that allows for more advanced subtitles than the conventional SRT and similar formats.' - },{ - format: 'ASS', - description: 'Advanced SubStation Alpha (ASS), technically SSA v4+, is a script for more advanced subtitles than SSA.' - } - ]); -}); +`.trim(), + { + delimiter: ";", + columns: true, + ignore_last_delimiters: 10, + }, + function (err, records) { + assert.deepStrictEqual(records, [ + { + format: "CSV", + description: + "CSV delimited text file that uses a comma, by default, to separate values.", + }, + { + format: "SSA", + description: + "SSA is a subtitle file format that allows for more advanced subtitles than the conventional SRT and similar formats.", + }, + { + format: "ASS", + description: + "Advanced SubStation Alpha (ASS), technically SSA v4+, is a script for more advanced subtitles than SSA.", + }, + ]); + }, +); diff --git a/packages/csv-parse/samples/option.info.js b/packages/csv-parse/samples/option.info.js index 40db8859b..5165195e7 100644 --- a/packages/csv-parse/samples/option.info.js +++ b/packages/csv-parse/samples/option.info.js @@ -1,24 +1,25 @@ - -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; const data = "a,b,c"; const records = parse(data, { - info: true + info: true, }); -assert.deepStrictEqual(records, [{ - info: { - bytes: 5, - columns: false, - comment_lines: 0, - empty_lines: 0, - error: undefined, - header: false, - index: 3, - invalid_field_length: 0, - lines: 1, - raw: undefined, - records: 1, +assert.deepStrictEqual(records, [ + { + info: { + bytes: 5, + columns: false, + comment_lines: 0, + empty_lines: 0, + error: undefined, + header: false, + index: 3, + invalid_field_length: 0, + lines: 1, + raw: undefined, + records: 1, + }, + record: ["a", "b", "c"], }, - record: [ 'a', 'b', 'c' ] -}]); +]); diff --git a/packages/csv-parse/samples/option.ltrim.js b/packages/csv-parse/samples/option.ltrim.js index 47cf27cd0..c79626c98 100644 --- a/packages/csv-parse/samples/option.ltrim.js +++ b/packages/csv-parse/samples/option.ltrim.js @@ -1,19 +1,12 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const data = [ - 'a ,1', - 'b, 2 ', - ' c,3' -].join('\n'); +const data = ["a ,1", "b, 2 ", " c,3"].join("\n"); const records = parse(data, { - ltrim: true + ltrim: true, }); -assert.deepStrictEqual( - records, [ - [ 'a ', '1' ], - [ 'b', '2 ' ], - [ 'c', '3' ] - ] -); +assert.deepStrictEqual(records, [ + ["a ", "1"], + ["b", "2 "], + ["c", "3"], +]); diff --git a/packages/csv-parse/samples/option.max_record_size.js b/packages/csv-parse/samples/option.max_record_size.js index 671175e33..14e512f90 100644 --- a/packages/csv-parse/samples/option.max_record_size.js +++ b/packages/csv-parse/samples/option.max_record_size.js @@ -1,14 +1,15 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` "first","last" "Paul-Émile","Victor" -`.trim(), { - max_record_size: 10 -}, function(err){ - assert.ok( - /Max Record Size/.test(err.message) - ); -}); +`.trim(), + { + max_record_size: 10, + }, + function (err) { + assert.ok(/Max Record Size/.test(err.message)); + }, +); diff --git a/packages/csv-parse/samples/option.objname.column.js b/packages/csv-parse/samples/option.objname.column.js index c4222a69e..0185e5c52 100644 --- a/packages/csv-parse/samples/option.objname.column.js +++ b/packages/csv-parse/samples/option.objname.column.js @@ -1,13 +1,12 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const records = parse('c1,c2,c3\na,b,c\nd,e,f', { +const records = parse("c1,c2,c3\na,b,c\nd,e,f", { columns: true, - objname: 'c2' + objname: "c2", }); assert.deepStrictEqual(records, { - b: { c1: 'a', c2: 'b', c3: 'c' }, - e: { c1: 'd', c2: 'e', c3: 'f' } + b: { c1: "a", c2: "b", c3: "c" }, + e: { c1: "d", c2: "e", c3: "f" }, }); diff --git a/packages/csv-parse/samples/option.objname.index.js b/packages/csv-parse/samples/option.objname.index.js index 3f5761735..8dfba4204 100644 --- a/packages/csv-parse/samples/option.objname.index.js +++ b/packages/csv-parse/samples/option.objname.index.js @@ -1,12 +1,11 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const records = parse('a,b,c\nd,e,f', { - objname: 1 +const records = parse("a,b,c\nd,e,f", { + objname: 1, }); assert.deepStrictEqual(records, { - b: ['a', 'b', 'c'], - e: ['d', 'e', 'f'] + b: ["a", "b", "c"], + e: ["d", "e", "f"], }); diff --git a/packages/csv-parse/samples/option.on_record.alter.js b/packages/csv-parse/samples/option.on_record.alter.js index 24d1553eb..bb07c8aa2 100644 --- a/packages/csv-parse/samples/option.on_record.alter.js +++ b/packages/csv-parse/samples/option.on_record.alter.js @@ -1,18 +1,18 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` a.1,a.2,a.3 b.1,b.2,b.3 -`.trim(), { - on_record: (record, {lines}) => - [lines, record[2], record[0]] -}, function(err, records){ - assert.deepStrictEqual( - records, [ - [1, 'a.3', 'a.1'], - [2, 'b.3', 'b.1'] - ] - ); -}); +`.trim(), + { + on_record: (record, { lines }) => [lines, record[2], record[0]], + }, + function (err, records) { + assert.deepStrictEqual(records, [ + [1, "a.3", "a.1"], + [2, "b.3", "b.1"], + ]); + }, +); diff --git a/packages/csv-parse/samples/option.on_record.filter.js b/packages/csv-parse/samples/option.on_record.filter.js index 154ecd15a..036ca1008 100644 --- a/packages/csv-parse/samples/option.on_record.filter.js +++ b/packages/csv-parse/samples/option.on_record.filter.js @@ -1,19 +1,16 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` line 1 line 2 line 3 -`.trim(), { - on_record: (record, {lines}) => - lines === 2 ? null : record -}, function(err, records){ - assert.deepStrictEqual( - records, [ - ['line 1'], - ['line 3'] - ] - ); -}); +`.trim(), + { + on_record: (record, { lines }) => (lines === 2 ? null : record), + }, + function (err, records) { + assert.deepStrictEqual(records, [["line 1"], ["line 3"]]); + }, +); diff --git a/packages/csv-parse/samples/option.quote.default.js b/packages/csv-parse/samples/option.quote.default.js index 9942bcbe3..f2ef0ea75 100644 --- a/packages/csv-parse/samples/option.quote.default.js +++ b/packages/csv-parse/samples/option.quote.default.js @@ -1,15 +1,14 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const records = parse(` +const records = parse( + ` a,"b",c "d",e,"f" -`.trim()); - -assert.deepStrictEqual( - records, [ - ['a', 'b', 'c'], - ['d', 'e', 'f'] - ] +`.trim(), ); + +assert.deepStrictEqual(records, [ + ["a", "b", "c"], + ["d", "e", "f"], +]); diff --git a/packages/csv-parse/samples/option.quote.escape.js b/packages/csv-parse/samples/option.quote.escape.js index 3660f31af..bbc09d227 100644 --- a/packages/csv-parse/samples/option.quote.escape.js +++ b/packages/csv-parse/samples/option.quote.escape.js @@ -1,15 +1,14 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const records = parse(` +const records = parse( + ` a,"b""b",c d,"e""e",f -`.trim()); - -assert.deepStrictEqual( - records, [ - ['a', 'b"b', 'c'], - ['d', 'e"e', 'f'] - ] +`.trim(), ); + +assert.deepStrictEqual(records, [ + ["a", 'b"b', "c"], + ["d", 'e"e', "f"], +]); diff --git a/packages/csv-parse/samples/option.raw.js b/packages/csv-parse/samples/option.raw.js index da9bb5ddf..4fa075cb6 100644 --- a/packages/csv-parse/samples/option.raw.js +++ b/packages/csv-parse/samples/option.raw.js @@ -1,13 +1,16 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` a,b,c d,e,f -`.trim(), {raw: true}, (err, records) => { - assert.deepStrictEqual(records, [ - { record: [ 'a', 'b', 'c' ], raw: 'a,b,c\n' }, - { record: [ 'd', 'e', 'f' ], raw: 'd,e,f' } - ]); -}); +`.trim(), + { raw: true }, + (err, records) => { + assert.deepStrictEqual(records, [ + { record: ["a", "b", "c"], raw: "a,b,c\n" }, + { record: ["d", "e", "f"], raw: "d,e,f" }, + ]); + }, +); diff --git a/packages/csv-parse/samples/option.record_delimiter.array.js b/packages/csv-parse/samples/option.record_delimiter.array.js index 31e28aa7c..b35fc3c93 100644 --- a/packages/csv-parse/samples/option.record_delimiter.array.js +++ b/packages/csv-parse/samples/option.record_delimiter.array.js @@ -1,13 +1,12 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const data = 'a,b,c&&d,e,f||h,i,j'; +const data = "a,b,c&&d,e,f||h,i,j"; const records = parse(data, { - record_delimiter: ['&&', '||'] + record_delimiter: ["&&", "||"], }); assert.deepStrictEqual(records, [ - [ 'a', 'b', 'c' ], - [ 'd', 'e', 'f' ], - [ 'h', 'i', 'j' ] + ["a", "b", "c"], + ["d", "e", "f"], + ["h", "i", "j"], ]); diff --git a/packages/csv-parse/samples/option.record_delimiter.js b/packages/csv-parse/samples/option.record_delimiter.js index f8dfebbec..8fd34b7e6 100644 --- a/packages/csv-parse/samples/option.record_delimiter.js +++ b/packages/csv-parse/samples/option.record_delimiter.js @@ -1,12 +1,11 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const data = 'a,b,c&&d,e,f'; +const data = "a,b,c&&d,e,f"; const records = parse(data, { - record_delimiter: '&&' + record_delimiter: "&&", }); assert.deepStrictEqual(records, [ - [ 'a', 'b', 'c' ], - [ 'd', 'e', 'f' ] + ["a", "b", "c"], + ["d", "e", "f"], ]); diff --git a/packages/csv-parse/samples/option.relax_column_count.columns.js b/packages/csv-parse/samples/option.relax_column_count.columns.js index 50c6ad03d..9401b0339 100644 --- a/packages/csv-parse/samples/option.relax_column_count.columns.js +++ b/packages/csv-parse/samples/option.relax_column_count.columns.js @@ -1,21 +1,24 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` lastname,firstname,fullname Ritchie Lovelace,Ada,"Augusta Ada King, Countess of Lovelace" -`.trim(), { - relax_column_count: true, - columns: true -}, function(err, records){ - assert.deepStrictEqual( - records, [ - { lastname: 'Ritchie' }, - { lastname: 'Lovelace', - firstname: 'Ada', - fullname: 'Augusta Ada King, Countess of Lovelace' } - ] - ); -}); +`.trim(), + { + relax_column_count: true, + columns: true, + }, + function (err, records) { + assert.deepStrictEqual(records, [ + { lastname: "Ritchie" }, + { + lastname: "Lovelace", + firstname: "Ada", + fullname: "Augusta Ada King, Countess of Lovelace", + }, + ]); + }, +); diff --git a/packages/csv-parse/samples/option.relax_column_count.js b/packages/csv-parse/samples/option.relax_column_count.js index 973294495..4c93369ab 100644 --- a/packages/csv-parse/samples/option.relax_column_count.js +++ b/packages/csv-parse/samples/option.relax_column_count.js @@ -1,19 +1,20 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` "a 1","a 2" "b 1" "c 1","c 2","c 3" -`.trim(), { - relax_column_count: true -}, function(err, records){ - assert.deepStrictEqual( - records, [ - ['a 1', 'a 2'], - ['b 1'], - ['c 1', 'c 2', 'c 3'] - ] - ); -}); +`.trim(), + { + relax_column_count: true, + }, + function (err, records) { + assert.deepStrictEqual(records, [ + ["a 1", "a 2"], + ["b 1"], + ["c 1", "c 2", "c 3"], + ]); + }, +); diff --git a/packages/csv-parse/samples/option.relax_column_count.record_inconsistent_columns.js b/packages/csv-parse/samples/option.relax_column_count.record_inconsistent_columns.js index 3efb1ec32..df0bd40fa 100644 --- a/packages/csv-parse/samples/option.relax_column_count.record_inconsistent_columns.js +++ b/packages/csv-parse/samples/option.relax_column_count.record_inconsistent_columns.js @@ -1,23 +1,20 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const records = parse('1,2\nin:va:lid\n3,4', { - columns: ['a', 'b'], +const records = parse("1,2\nin:va:lid\n3,4", { + columns: ["a", "b"], relax_column_count: true, raw: true, - on_record: ({raw, record}, {error}) => { - if(error && error.code === 'CSV_RECORD_INCONSISTENT_COLUMNS'){ - return raw.trim().split(':'); + on_record: ({ raw, record }, { error }) => { + if (error && error.code === "CSV_RECORD_INCONSISTENT_COLUMNS") { + return raw.trim().split(":"); } else { return record; } - } + }, }); -assert.deepStrictEqual( - records, [ - { a: '1', b: '2' }, - [ 'in', 'va', 'lid' ], - { a: '3', b: '4' } - ] -); +assert.deepStrictEqual(records, [ + { a: "1", b: "2" }, + ["in", "va", "lid"], + { a: "3", b: "4" }, +]); diff --git a/packages/csv-parse/samples/option.relax_column_count.record_inconsistent_length.js b/packages/csv-parse/samples/option.relax_column_count.record_inconsistent_length.js index 9be7dbb4a..af42855ce 100644 --- a/packages/csv-parse/samples/option.relax_column_count.record_inconsistent_length.js +++ b/packages/csv-parse/samples/option.relax_column_count.record_inconsistent_length.js @@ -1,22 +1,19 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const records = parse('1,2\nin:va:lid\n3,4', { +const records = parse("1,2\nin:va:lid\n3,4", { relax_column_count: true, raw: true, - on_record: ({raw, record}, {error}) => { - if(error && error.code === 'CSV_RECORD_INCONSISTENT_FIELDS_LENGTH'){ - return raw.trim().split(':'); + on_record: ({ raw, record }, { error }) => { + if (error && error.code === "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH") { + return raw.trim().split(":"); } else { return record; } - } + }, }); -assert.deepStrictEqual( - records, [ - [ '1', '2' ], - [ 'in', 'va', 'lid' ], - [ '3', '4' ] - ] -); +assert.deepStrictEqual(records, [ + ["1", "2"], + ["in", "va", "lid"], + ["3", "4"], +]); diff --git a/packages/csv-parse/samples/option.relax_column_count_less.js b/packages/csv-parse/samples/option.relax_column_count_less.js index 46a6af0c7..0f9cd8505 100644 --- a/packages/csv-parse/samples/option.relax_column_count_less.js +++ b/packages/csv-parse/samples/option.relax_column_count_less.js @@ -1,15 +1,18 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` a,b,c d,e -`.trim(), { - relax_column_count_less: true -}, (err, records) => { - assert.deepStrictEqual(records, [ - ['a', 'b', 'c'], - ['d', 'e'] - ]); -}); +`.trim(), + { + relax_column_count_less: true, + }, + (err, records) => { + assert.deepStrictEqual(records, [ + ["a", "b", "c"], + ["d", "e"], + ]); + }, +); diff --git a/packages/csv-parse/samples/option.relax_column_count_more.js b/packages/csv-parse/samples/option.relax_column_count_more.js index cdfc35236..b45cbf99c 100644 --- a/packages/csv-parse/samples/option.relax_column_count_more.js +++ b/packages/csv-parse/samples/option.relax_column_count_more.js @@ -1,15 +1,18 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` a,b c,d,e -`.trim(), { - relax_column_count_more: true -}, (err, records) => { - assert.deepStrictEqual(records, [ - ['a', 'b'], - ['c', 'd', 'e'] - ]); -}); +`.trim(), + { + relax_column_count_more: true, + }, + (err, records) => { + assert.deepStrictEqual(records, [ + ["a", "b"], + ["c", "d", "e"], + ]); + }, +); diff --git a/packages/csv-parse/samples/option.relax_quotes.js b/packages/csv-parse/samples/option.relax_quotes.js index dba2a650b..0d7bc9469 100644 --- a/packages/csv-parse/samples/option.relax_quotes.js +++ b/packages/csv-parse/samples/option.relax_quotes.js @@ -1,13 +1,14 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` a,some"text,c -`.trim(), { - relax_quotes: true -}, (err, records) => { - assert.deepStrictEqual(records, [ - ['a', 'some"text', 'c'] - ]); -}); +`.trim(), + { + relax_quotes: true, + }, + (err, records) => { + assert.deepStrictEqual(records, [["a", 'some"text', "c"]]); + }, +); diff --git a/packages/csv-parse/samples/option.rtrim.js b/packages/csv-parse/samples/option.rtrim.js index 459b56ea0..7647d21e4 100644 --- a/packages/csv-parse/samples/option.rtrim.js +++ b/packages/csv-parse/samples/option.rtrim.js @@ -1,19 +1,12 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const data = [ - 'a ,1', - 'b, 2 ', - ' c,3' -].join('\n'); +const data = ["a ,1", "b, 2 ", " c,3"].join("\n"); const records = parse(data, { - rtrim: true + rtrim: true, }); -assert.deepStrictEqual( - records, [ - [ 'a', '1' ], - [ 'b', ' 2' ], - [ ' c', '3' ] - ] -); +assert.deepStrictEqual(records, [ + ["a", "1"], + ["b", " 2"], + [" c", "3"], +]); diff --git a/packages/csv-parse/samples/option.skip_empty_lines.js b/packages/csv-parse/samples/option.skip_empty_lines.js index fe168232f..fb2a6cd09 100644 --- a/packages/csv-parse/samples/option.skip_empty_lines.js +++ b/packages/csv-parse/samples/option.skip_empty_lines.js @@ -1,18 +1,18 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const records = parse(` +const records = parse( + ` "a","b","c" "d","e","f" -`, { - skip_empty_lines: true -}); - -assert.deepStrictEqual( - records, [ - ['a', 'b', 'c'], - ['d', 'e', 'f'] - ] +`, + { + skip_empty_lines: true, + }, ); + +assert.deepStrictEqual(records, [ + ["a", "b", "c"], + ["d", "e", "f"], +]); diff --git a/packages/csv-parse/samples/option.skip_empty_lines.trim.js b/packages/csv-parse/samples/option.skip_empty_lines.trim.js index cf7f60dec..87b6b0191 100644 --- a/packages/csv-parse/samples/option.skip_empty_lines.trim.js +++ b/packages/csv-parse/samples/option.skip_empty_lines.trim.js @@ -1,19 +1,19 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const records = parse(` +const records = parse( + ` "a","b","c" \t "d","e","f" -`, { - skip_empty_lines: true, - trim: true -}); - -assert.deepStrictEqual( - records, [ - ['a', 'b', 'c'], - ['d', 'e', 'f'] - ] +`, + { + skip_empty_lines: true, + trim: true, + }, ); + +assert.deepStrictEqual(records, [ + ["a", "b", "c"], + ["d", "e", "f"], +]); diff --git a/packages/csv-parse/samples/option.skip_records_with_empty_values.js b/packages/csv-parse/samples/option.skip_records_with_empty_values.js index 2d8867305..6028dbfb4 100644 --- a/packages/csv-parse/samples/option.skip_records_with_empty_values.js +++ b/packages/csv-parse/samples/option.skip_records_with_empty_values.js @@ -1,16 +1,19 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` a,b,c , ,\t d,e,f -`.trim(), { - skip_records_with_empty_values: true -}, (err, records) => { - assert.deepStrictEqual(records, [ - ['a', 'b', 'c'], - ['d', 'e', 'f'] - ]); -}); +`.trim(), + { + skip_records_with_empty_values: true, + }, + (err, records) => { + assert.deepStrictEqual(records, [ + ["a", "b", "c"], + ["d", "e", "f"], + ]); + }, +); diff --git a/packages/csv-parse/samples/option.skip_records_with_error.js b/packages/csv-parse/samples/option.skip_records_with_error.js index b1b6c97d1..7d2d7a8cc 100644 --- a/packages/csv-parse/samples/option.skip_records_with_error.js +++ b/packages/csv-parse/samples/option.skip_records_with_error.js @@ -1,25 +1,27 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -const parser = parse({ - skip_records_with_error: true -}, function(err, records){ - assert.deepStrictEqual( - records, [ - ['a', 'b', 'c'], - ['d', 'e', 'f'], - ['h', 'i', 'j'] - ] - ); -}); -parser.on('skip', function(err){ +const parser = parse( + { + skip_records_with_error: true, + }, + function (err, records) { + assert.deepStrictEqual(records, [ + ["a", "b", "c"], + ["d", "e", "f"], + ["h", "i", "j"], + ]); + }, +); +parser.on("skip", function (err) { assert(/^Invalid Closing Quote/.test(err.message)); }); -parser.write(` +parser.write( + ` "a","b","c" "d","e","f" "invalid"," " ","record" "h","i","j" -`.trim()); +`.trim(), +); parser.end(); diff --git a/packages/csv-parse/samples/option.to.js b/packages/csv-parse/samples/option.to.js index 89590506b..a2032518a 100644 --- a/packages/csv-parse/samples/option.to.js +++ b/packages/csv-parse/samples/option.to.js @@ -1,24 +1,28 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse(` +parse( + ` a,b 1,2 3,4 5,6 -`.trim(), { - columns: true, - to: 2 -}, function(err, records){ - console.info(err, records); - assert.deepStrictEqual( - records, [{ - a: '1', - b: '2' - }, { - a: '3', - b: '4' - }] - ); -}); +`.trim(), + { + columns: true, + to: 2, + }, + function (err, records) { + console.info(err, records); + assert.deepStrictEqual(records, [ + { + a: "1", + b: "2", + }, + { + a: "3", + b: "4", + }, + ]); + }, +); diff --git a/packages/csv-parse/samples/option.to_line.js b/packages/csv-parse/samples/option.to_line.js index a08bbec85..9ea949713 100644 --- a/packages/csv-parse/samples/option.to_line.js +++ b/packages/csv-parse/samples/option.to_line.js @@ -1,17 +1,17 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const records = parse(` +const records = parse( + ` a,1 b,1 x,x -`.trim(), { - to_line: 2 -}); -assert.deepStrictEqual( - records, [ - [ 'a', '1' ], - [ 'b', '1' ] - ] +`.trim(), + { + to_line: 2, + }, ); +assert.deepStrictEqual(records, [ + ["a", "1"], + ["b", "1"], +]); diff --git a/packages/csv-parse/samples/option.trim.js b/packages/csv-parse/samples/option.trim.js index b8a04fbe7..900326a92 100644 --- a/packages/csv-parse/samples/option.trim.js +++ b/packages/csv-parse/samples/option.trim.js @@ -1,14 +1,11 @@ +import assert from "node:assert"; +import { parse } from "csv-parse/sync"; -import assert from 'node:assert'; -import { parse } from 'csv-parse/sync'; - -const records = parse('a ,1\nb, 2\n c,3', { - trim: true +const records = parse("a ,1\nb, 2\n c,3", { + trim: true, }); -assert.deepStrictEqual( - records, [ - [ 'a', '1' ], - [ 'b', '2' ], - [ 'c', '3' ] - ] -); +assert.deepStrictEqual(records, [ + ["a", "1"], + ["b", "2"], + ["c", "3"], +]); diff --git a/packages/csv-parse/samples/recipe.async.iterator.js b/packages/csv-parse/samples/recipe.async.iterator.js index 232454598..25221c7ab 100644 --- a/packages/csv-parse/samples/recipe.async.iterator.js +++ b/packages/csv-parse/samples/recipe.async.iterator.js @@ -1,16 +1,15 @@ +import fs from "node:fs"; +import { parse } from "csv-parse"; -import fs from 'node:fs'; -import { parse } from 'csv-parse'; - -const __dirname = new URL('.', import.meta.url).pathname; +const __dirname = new URL(".", import.meta.url).pathname; const processFile = async () => { const records = []; - const parser = fs - .createReadStream(`${__dirname}/fs_read.csv`) - .pipe(parse({ - // CSV options if any - })); + const parser = fs.createReadStream(`${__dirname}/fs_read.csv`).pipe( + parse({ + // CSV options if any + }), + ); for await (const record of parser) { // Work with each record records.push(record); diff --git a/packages/csv-parse/samples/recipe.file.js b/packages/csv-parse/samples/recipe.file.js index ed202683a..4ea59d42b 100644 --- a/packages/csv-parse/samples/recipe.file.js +++ b/packages/csv-parse/samples/recipe.file.js @@ -1,27 +1,30 @@ +import assert from "node:assert"; +import { promises as fs } from "fs"; // 'fs/promises' not available in node 12 +import os from "os"; +import { parse } from "../lib/sync.js"; -import assert from 'node:assert'; -import {promises as fs} from 'fs'; // 'fs/promises' not available in node 12 -import os from 'os'; -import { parse } from '../lib/sync.js'; - -/* hide-next-line */ -/* eslint-disable indent */ /* hide-next-line */ -(async() => { -// Prepare the dataset -await fs.writeFile(`${os.tmpdir()}/input.csv`, [ - '\ufeff', // BOM - 'a,1\n', // First record - 'b,2\n' // Second record -].join(''), 'utf8'); -// Read the content -const content = await fs.readFile(`${os.tmpdir()}/input.csv`); -// Parse the CSV content -const records = parse(content, {bom: true}); -// Validate the records -assert.deepStrictEqual(records, [ - [ 'a', '1' ], - [ 'b', '2' ] -]); + /* hide-next-line */ +(async () => { + // Prepare the dataset + await fs.writeFile( + `${os.tmpdir()}/input.csv`, + [ + "\ufeff", // BOM + "a,1\n", // First record + "b,2\n", // Second record + ].join(""), + "utf8", + ); + // Read the content + const content = await fs.readFile(`${os.tmpdir()}/input.csv`); + // Parse the CSV content + const records = parse(content, { bom: true }); + // Validate the records + assert.deepStrictEqual(records, [ + ["a", "1"], + ["b", "2"], + ]); + /* hide-next-line */ })(); diff --git a/packages/csv-parse/samples/recipe.file.utf16le.js b/packages/csv-parse/samples/recipe.file.utf16le.js index fc3c1c1a1..6519f6348 100644 --- a/packages/csv-parse/samples/recipe.file.utf16le.js +++ b/packages/csv-parse/samples/recipe.file.utf16le.js @@ -1,31 +1,28 @@ +import assert from "node:assert"; +import { promises as fs } from "fs"; +import os from "os"; +import { parse } from "../lib/sync.js"; -import assert from 'node:assert'; -import {promises as fs} from 'fs'; -import os from 'os'; -import { parse } from '../lib/sync.js'; - -/* hide-next-line */ -/* eslint-disable indent */ /* hide-next-line */ -(async() => { -// Prepare the dataset -await fs.writeFile(`${os.tmpdir()}/input.csv`, Buffer.from([ - '\ufeff', - `a€b€c`, - '\n', - `d€e€f` -].join(''), 'utf16le')); -// Read the content -const content = await fs.readFile(`${os.tmpdir()}/input.csv`); -// Parse the CSV content -const records = parse(content, { - delimiter: '€', - encoding: 'utf16le' -}); -// Validate the records -assert.deepStrictEqual(records, [ - [ 'a', 'b', 'c' ], - [ 'd', 'e', 'f' ] -]); + /* hide-next-line */ +(async () => { + // Prepare the dataset + await fs.writeFile( + `${os.tmpdir()}/input.csv`, + Buffer.from(["\ufeff", `a€b€c`, "\n", `d€e€f`].join(""), "utf16le"), + ); + // Read the content + const content = await fs.readFile(`${os.tmpdir()}/input.csv`); + // Parse the CSV content + const records = parse(content, { + delimiter: "€", + encoding: "utf16le", + }); + // Validate the records + assert.deepStrictEqual(records, [ + ["a", "b", "c"], + ["d", "e", "f"], + ]); + /* hide-next-line */ })(); diff --git a/packages/csv-parse/samples/recipe.pipe.js b/packages/csv-parse/samples/recipe.pipe.js index fc38b8223..3503fb644 100644 --- a/packages/csv-parse/samples/recipe.pipe.js +++ b/packages/csv-parse/samples/recipe.pipe.js @@ -1,19 +1,21 @@ - -import { parse } from 'csv-parse'; -import { generate } from 'csv-generate'; -import { transform } from 'stream-transform'; +import { parse } from "csv-parse"; +import { generate } from "csv-generate"; +import { transform } from "stream-transform"; const generator = generate({ - length: 20 + length: 20, }); const parser = parse({ - delimiter: ':' -}); -const transformer = transform((record, callback) => { - setTimeout(() => { - callback(null, record.join(' ')+'\n'); - }, 500); -}, { - parallel: 5 + delimiter: ":", }); +const transformer = transform( + (record, callback) => { + setTimeout(() => { + callback(null, record.join(" ") + "\n"); + }, 500); + }, + { + parallel: 5, + }, +); generator.pipe(parser).pipe(transformer).pipe(process.stdout); diff --git a/packages/csv-parse/samples/recipe.promises.js b/packages/csv-parse/samples/recipe.promises.js index e3b52dd20..1230a7a0b 100644 --- a/packages/csv-parse/samples/recipe.promises.js +++ b/packages/csv-parse/samples/recipe.promises.js @@ -1,44 +1,44 @@ - -import assert from 'node:assert'; -import fs from 'node:fs'; -import os from 'node:os'; -import { parse } from 'csv-parse'; +import assert from "node:assert"; +import fs from "node:fs"; +import os from "node:os"; +import { parse } from "csv-parse"; // Note, the `stream/promises` module is only available // starting with Node.js version 16 -import { finished } from 'stream/promises'; +import { finished } from "stream/promises"; /* hide-next-line */ -/* eslint-disable indent */ -/* hide-next-line */ -(async() => { -// Prepare the dataset -await fs.promises.writeFile(`${os.tmpdir()}/input.csv`, [ - 'a,b,c', - '1,2,3' -].join('\n')); -// Read and process the CSV file -const processFile = async () => { - const records = []; - const parser = fs - .createReadStream(`${os.tmpdir()}/input.csv`) - .pipe(parse({ - // CSV options if any - })); - parser.on('readable', function(){ - let record; while ((record = parser.read()) !== null) { - // Work with each record - records.push(record); - } - }); - await finished(parser); - return records; -}; -// Parse the CSV content -const records = await processFile(); -// Validate the records -assert.deepStrictEqual(records, [ - [ 'a', 'b', 'c' ], - [ '1', '2', '3' ] -]); + /* hide-next-line */ +(async () => { + // Prepare the dataset + await fs.promises.writeFile( + `${os.tmpdir()}/input.csv`, + ["a,b,c", "1,2,3"].join("\n"), + ); + // Read and process the CSV file + const processFile = async () => { + const records = []; + const parser = fs.createReadStream(`${os.tmpdir()}/input.csv`).pipe( + parse({ + // CSV options if any + }), + ); + parser.on("readable", function () { + let record; + while ((record = parser.read()) !== null) { + // Work with each record + records.push(record); + } + }); + await finished(parser); + return records; + }; + // Parse the CSV content + const records = await processFile(); + // Validate the records + assert.deepStrictEqual(records, [ + ["a", "b", "c"], + ["1", "2", "3"], + ]); + /* hide-next-line */ })(); diff --git a/packages/csv-parse/samples/tsv.js b/packages/csv-parse/samples/tsv.js index a7ace2233..7fa4b6557 100644 --- a/packages/csv-parse/samples/tsv.js +++ b/packages/csv-parse/samples/tsv.js @@ -1,8 +1,10 @@ +import assert from "node:assert"; +import { parse } from "csv-parse"; -import assert from 'node:assert'; -import { parse } from 'csv-parse'; - -parse('1 2 3\ra b c', {delimiter: '\t'}, function(err, data){ - if(err) throw err; - assert.deepStrictEqual(data, [ [ '1', '2', '3' ], [ 'a', 'b', 'c' ] ]); +parse("1 2 3\ra b c", { delimiter: "\t" }, function (err, data) { + if (err) throw err; + assert.deepStrictEqual(data, [ + ["1", "2", "3"], + ["a", "b", "c"], + ]); }); diff --git a/packages/csv-parse/test/option.rtrim.coffee b/packages/csv-parse/test/option.rtrim.coffee index e0bb375ab..3e0d091e8 100644 --- a/packages/csv-parse/test/option.rtrim.coffee +++ b/packages/csv-parse/test/option.rtrim.coffee @@ -5,22 +5,18 @@ import { assert_error } from './api.assert_error.coffee' describe 'Option `rtrim`', -> it 'plain text', (next) -> - # coffeelint: disable=no_trailing_whitespace parse """ a b ,c d e f ,g h """, quote: "'", escape: "'", trim: true, (err, records) -> records.should.eql [['a b', 'c d'],['e f', 'g h']] unless err next err - # coffeelint: enable=no_trailing_whitespace it 'after quote', (next) -> - # coffeelint: disable=no_trailing_whitespace data = ''' 'a' ,'b' 'c' ,'d' ''' - # coffeelint: enable=no_trailing_whitespace parser = parse quote: "'", escape: "'", trim: true, (err, records) -> records.should.eql [["a", "b"],["c", "d"]] unless err next err @@ -31,7 +27,6 @@ describe 'Option `rtrim`', -> # 1st line: with field delimiter # 2nd line: with record delimiter # 3rd line: with end of file - # coffeelint: disable=no_trailing_whitespace parse """ 'a''' ,'b''' 'c''','d''' @@ -39,15 +34,12 @@ describe 'Option `rtrim`', -> """, quote: "'", escape: "'", trim: true, (err, records) -> records.should.eql [["a'", "b'"],["c'", "d'"],["e'", "f'"]] unless err next err - # coffeelint: enable=no_trailing_whitespace it 'with whitespaces around quotes', (next) -> - # coffeelint: disable=no_trailing_whitespace data = ''' "a b " ,"c d " "e f " ,"g h " ''' - # coffeelint: enable=no_trailing_whitespace parser = parse rtrim: true, (err, records) -> records.should.eql [['a b ', 'c d '],['e f ', 'g h ']] unless err next err diff --git a/packages/csv-stringify/.eslintrc.yml b/packages/csv-stringify/.eslintrc.yml deleted file mode 100644 index 4581986eb..000000000 --- a/packages/csv-stringify/.eslintrc.yml +++ /dev/null @@ -1,21 +0,0 @@ -env: - commonjs: true - es6: true - node: true -extends: "eslint:recommended" -globals: - Atomics: "readonly" - SharedArrayBuffer: "readonly" -parserOptions: - ecmaVersion: "latest" - sourceType: "module" -rules: - no-var: "error" - semi: "error" - indent: ["error", 2] - linebreak-style: ["error", "unix"] - no-multi-spaces: "error" - space-in-parens: "error" - no-multiple-empty-lines: "error" - prefer-const: "error" - no-use-before-define: "error" diff --git a/packages/csv-stringify/.travis.yml b/packages/csv-stringify/.travis.yml deleted file mode 100644 index acf72d76e..000000000 --- a/packages/csv-stringify/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - "10" - - "12" - - "14" diff --git a/packages/csv-stringify/coffeelint.json b/packages/csv-stringify/coffeelint.json deleted file mode 100644 index db57f258d..000000000 --- a/packages/csv-stringify/coffeelint.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "arrow_spacing": { - "level": "ignore" - }, - "braces_spacing": { - "level": "ignore", - "spaces": 0, - "empty_object_spaces": 0 - }, - "camel_case_classes": { - "level": "error" - }, - "coffeescript_error": { - "level": "error" - }, - "colon_assignment_spacing": { - "level": "ignore", - "spacing": { - "left": 0, - "right": 0 - } - }, - "cyclomatic_complexity": { - "level": "ignore", - "value": 10 - }, - "duplicate_key": { - "level": "error" - }, - "empty_constructor_needs_parens": { - "level": "ignore" - }, - "ensure_comprehensions": { - "level": "warn" - }, - "eol_last": { - "level": "ignore" - }, - "indentation": { - "value": 2, - "level": "error" - }, - "line_endings": { - "level": "error", - "value": "unix" - }, - "max_line_length": { - "value": 80, - "level": "ignore", - "limitComments": true - }, - "missing_fat_arrows": { - "level": "ignore", - "is_strict": false - }, - "newlines_after_classes": { - "value": 3, - "level": "ignore" - }, - "no_backticks": { - "level": "error" - }, - "no_debugger": { - "level": "warn", - "console": false - }, - "no_empty_functions": { - "level": "ignore" - }, - "no_empty_param_list": { - "level": "ignore" - }, - "no_implicit_braces": { - "level": "ignore", - "strict": true - }, - "no_implicit_parens": { - "level": "ignore", - "strict": true - }, - "no_interpolation_in_single_quotes": { - "level": "ignore" - }, - "no_nested_string_interpolation": { - "level": "warn" - }, - "no_plusplus": { - "level": "ignore" - }, - "no_private_function_fat_arrows": { - "level": "warn" - }, - "no_stand_alone_at": { - "level": "ignore" - }, - "no_tabs": { - "level": "error" - }, - "no_this": { - "level": "ignore" - }, - "no_throwing_strings": { - "level": "error" - }, - "no_trailing_semicolons": { - "level": "error" - }, - "no_trailing_whitespace": { - "level": "error", - "allowed_in_comments": false, - "allowed_in_empty_lines": true - }, - "no_unnecessary_double_quotes": { - "level": "ignore" - }, - "no_unnecessary_fat_arrows": { - "level": "warn" - }, - "non_empty_constructor_needs_parens": { - "level": "ignore" - }, - "prefer_english_operator": { - "level": "ignore", - "doubleNotLevel": "ignore" - }, - "space_operators": { - "level": "ignore" - }, - "spacing_after_comma": { - "level": "ignore" - }, - "transform_messes_up_line_numbers": { - "level": "warn" - } -} diff --git a/packages/csv-stringify/dist/cjs/index.cjs b/packages/csv-stringify/dist/cjs/index.cjs index 4d8e91d6f..1e8bad3f4 100644 --- a/packages/csv-stringify/dist/cjs/index.cjs +++ b/packages/csv-stringify/dist/cjs/index.cjs @@ -4,136 +4,163 @@ var stream = require('stream'); class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = Buffer.isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = Buffer.isBuffer(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; // Lodash implementation of `get` -const charCodeOfDot = '.'.charCodeAt(0); +const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", +); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; -const getTag = function(value){ +const getTag = function (value) { return Object.prototype.toString.call(value); }; -const isSymbol = function(value){ +const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; -const isKey = function(value, object){ - if(Array.isArray(value)){ +const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; -const stringToPath = function(string){ +const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; -const castPath = function(value, object){ - if(Array.isArray(value)){ +const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; -const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; +const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; -const get = function(object, path){ +const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; -const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ +const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -141,238 +168,288 @@ const normalize_columns = function(columns){ return [undefined, columns]; }; -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts) { +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(Buffer.isBuffer(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (Buffer.isBuffer(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (Buffer.isBuffer(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (Buffer.isBuffer(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(Buffer.isBuffer(options.escape)){ + } else if (Buffer.isBuffer(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(Buffer.isBuffer(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (Buffer.isBuffer(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); -const stringifier = function(options, state, info){ +const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -381,96 +458,136 @@ const stringifier = function(options, state, info){ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -480,171 +597,190 @@ const stringifier = function(options, state, info){ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; +/* +CSV Stringify + +Please look at the [project documentation](https://csv.js.org/stringify/) for +additional information. +*/ + + class Stringifier extends stream.Transform { - constructor(opts = {}){ - super({...{writableObjectMode: true}, ...opts}); + constructor(opts = {}) { + super({ ...{ writableObjectMode: true }, ...opts }); const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; // Expose options this.options = options; // Internal state this.state = { - stop: false + stop: false, }; // Information this.info = { - records: 0 + records: 0, }; this.api = stringifier(this.options, this.state, this.info); this.api.options.on_record = (...args) => { - this.emit('record', ...args); + this.emit("record", ...args); }; } - _transform(chunk, encoding, callback){ - if(this.state.stop === true){ + _transform(chunk, encoding, callback) { + if (this.state.stop === true) { return; } const err = this.api.__transform(chunk, this.push.bind(this)); - if(err !== undefined){ + if (err !== undefined) { this.state.stop = true; } callback(err); } - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { // Note, Node.js 12 call flush even after an error, we must prevent // `callback` from being called in flush without any error. return; } - if(this.info.records === 0){ + if (this.info.records === 0) { this.api.bom(this.push.bind(this)); const err = this.api.headers(this.push.bind(this)); - if(err) callback(err); + if (err) callback(err); } callback(); } } -const stringify = function(){ +const stringify = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (Array.isArray(argument))){ + if (data === undefined && Array.isArray(argument)) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` + } else { + throw new CsvError("CSV_INVALID_ARGUMENT", [ + "Invalid argument:", + `got ${JSON.stringify(argument)} at index ${i}`, ]); } } const stringifier = new Stringifier(options); - if(callback){ + if (callback) { const chunks = []; - stringifier.on('readable', function(){ + stringifier.on("readable", function () { let chunk; - while((chunk = this.read()) !== null){ + while ((chunk = this.read()) !== null) { chunks.push(chunk); } }); - stringifier.on('error', function(err){ + stringifier.on("error", function (err) { callback(err); }); - stringifier.on('end', function(){ + stringifier.on("end", function () { try { - callback(undefined, chunks.join('')); + callback(undefined, chunks.join("")); } catch (err) { // This can happen if the `chunks` is extremely long; it may throw // "Cannot create a string longer than 0x1fffffe8 characters" @@ -654,17 +790,17 @@ const stringify = function(){ } }); } - if(data !== undefined){ - const writer = function(){ - for(const record of data){ + if (data !== undefined) { + const writer = function () { + for (const record of data) { stringifier.write(record); } stringifier.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv-stringify/dist/cjs/sync.cjs b/packages/csv-stringify/dist/cjs/sync.cjs index a92b0575d..034ef2a31 100644 --- a/packages/csv-stringify/dist/cjs/sync.cjs +++ b/packages/csv-stringify/dist/cjs/sync.cjs @@ -2,119 +2,142 @@ // Lodash implementation of `get` -const charCodeOfDot = '.'.charCodeAt(0); +const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", +); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; -const getTag = function(value){ +const getTag = function (value) { return Object.prototype.toString.call(value); }; -const isSymbol = function(value){ +const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; -const isKey = function(value, object){ - if(Array.isArray(value)){ +const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; -const stringToPath = function(string){ +const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; -const castPath = function(value, object){ - if(Array.isArray(value)){ +const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; -const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; +const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; -const get = function(object, path){ +const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; -const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; -const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ +const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -124,253 +147,307 @@ const normalize_columns = function(columns){ class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = Buffer.isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = Buffer.isBuffer(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts) { +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(Buffer.isBuffer(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (Buffer.isBuffer(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (Buffer.isBuffer(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (Buffer.isBuffer(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(Buffer.isBuffer(options.escape)){ + } else if (Buffer.isBuffer(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(Buffer.isBuffer(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (Buffer.isBuffer(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); -const stringifier = function(options, state, info){ +const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -379,96 +456,136 @@ const stringifier = function(options, state, info){ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -478,121 +595,132 @@ const stringifier = function(options, state, info){ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; -const stringify = function(records, opts={}){ +const stringify = function (records, opts = {}) { const data = []; const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; const state = { - stop: false + stop: false, }; // Information const info = { - records: 0 + records: 0, }; const api = stringifier(options, state, info); - for(const record of records){ - const err = api.__transform(record, function(record){ + for (const record of records) { + const err = api.__transform(record, function (record) { data.push(record); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - if(data.length === 0){ + if (data.length === 0) { api.bom((d) => { data.push(d); }); const err = api.headers((headers) => { data.push(headers); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - return data.join(''); + return data.join(""); }; exports.stringify = stringify; diff --git a/packages/csv-stringify/dist/esm/index.js b/packages/csv-stringify/dist/esm/index.js index 5e161de9c..1bc116ad3 100644 --- a/packages/csv-stringify/dist/esm/index.js +++ b/packages/csv-stringify/dist/esm/index.js @@ -28,7 +28,7 @@ EventEmitter.init = function() { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5126,136 +5126,163 @@ Stream.prototype.pipe = function(dest, options) { class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; // Lodash implementation of `get` -const charCodeOfDot = '.'.charCodeAt(0); +const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", +); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; -const getTag = function(value){ +const getTag = function (value) { return Object.prototype.toString.call(value); }; -const isSymbol = function(value){ +const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; -const isKey = function(value, object){ - if(Array.isArray(value)){ +const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; -const stringToPath = function(string){ +const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; -const castPath = function(value, object){ - if(Array.isArray(value)){ +const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; -const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; +const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; -const get = function(object, path){ +const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; -const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ +const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -5263,238 +5290,288 @@ const normalize_columns = function(columns){ return [undefined, columns]; }; -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts) { +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer(options.escape)){ + } else if (isBuffer(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); -const stringifier = function(options, state, info){ +const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -5503,96 +5580,136 @@ const stringifier = function(options, state, info){ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -5602,171 +5719,190 @@ const stringifier = function(options, state, info){ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; +/* +CSV Stringify + +Please look at the [project documentation](https://csv.js.org/stringify/) for +additional information. +*/ + + class Stringifier extends Transform { - constructor(opts = {}){ - super({...{writableObjectMode: true}, ...opts}); + constructor(opts = {}) { + super({ ...{ writableObjectMode: true }, ...opts }); const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; // Expose options this.options = options; // Internal state this.state = { - stop: false + stop: false, }; // Information this.info = { - records: 0 + records: 0, }; this.api = stringifier(this.options, this.state, this.info); this.api.options.on_record = (...args) => { - this.emit('record', ...args); + this.emit("record", ...args); }; } - _transform(chunk, encoding, callback){ - if(this.state.stop === true){ + _transform(chunk, encoding, callback) { + if (this.state.stop === true) { return; } const err = this.api.__transform(chunk, this.push.bind(this)); - if(err !== undefined){ + if (err !== undefined) { this.state.stop = true; } callback(err); } - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { // Note, Node.js 12 call flush even after an error, we must prevent // `callback` from being called in flush without any error. return; } - if(this.info.records === 0){ + if (this.info.records === 0) { this.api.bom(this.push.bind(this)); const err = this.api.headers(this.push.bind(this)); - if(err) callback(err); + if (err) callback(err); } callback(); } } -const stringify = function(){ +const stringify = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (Array.isArray(argument))){ + if (data === undefined && Array.isArray(argument)) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` + } else { + throw new CsvError("CSV_INVALID_ARGUMENT", [ + "Invalid argument:", + `got ${JSON.stringify(argument)} at index ${i}`, ]); } } const stringifier = new Stringifier(options); - if(callback){ + if (callback) { const chunks = []; - stringifier.on('readable', function(){ + stringifier.on("readable", function () { let chunk; - while((chunk = this.read()) !== null){ + while ((chunk = this.read()) !== null) { chunks.push(chunk); } }); - stringifier.on('error', function(err){ + stringifier.on("error", function (err) { callback(err); }); - stringifier.on('end', function(){ + stringifier.on("end", function () { try { - callback(undefined, chunks.join('')); + callback(undefined, chunks.join("")); } catch (err) { // This can happen if the `chunks` is extremely long; it may throw // "Cannot create a string longer than 0x1fffffe8 characters" @@ -5776,17 +5912,17 @@ const stringify = function(){ } }); } - if(data !== undefined){ - const writer = function(){ - for(const record of data){ + if (data !== undefined) { + const writer = function () { + for (const record of data) { stringifier.write(record); } stringifier.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv-stringify/dist/esm/sync.js b/packages/csv-stringify/dist/esm/sync.js index 26d6e4dca..1e917450a 100644 --- a/packages/csv-stringify/dist/esm/sync.js +++ b/packages/csv-stringify/dist/esm/sync.js @@ -1972,119 +1972,142 @@ function isSlowBuffer (obj) { // Lodash implementation of `get` -const charCodeOfDot = '.'.charCodeAt(0); +const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", +); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; -const getTag = function(value){ +const getTag = function (value) { return Object.prototype.toString.call(value); }; -const isSymbol = function(value){ +const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; -const isKey = function(value, object){ - if(Array.isArray(value)){ +const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; -const stringToPath = function(string){ +const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; -const castPath = function(value, object){ - if(Array.isArray(value)){ +const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; -const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; +const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; -const get = function(object, path){ +const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; -const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; -const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ +const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -2094,253 +2117,307 @@ const normalize_columns = function(columns){ class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts) { +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer(options.escape)){ + } else if (isBuffer(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); -const stringifier = function(options, state, info){ +const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -2349,96 +2426,136 @@ const stringifier = function(options, state, info){ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -2448,121 +2565,132 @@ const stringifier = function(options, state, info){ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; -const stringify = function(records, opts={}){ +const stringify = function (records, opts = {}) { const data = []; const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; const state = { - stop: false + stop: false, }; // Information const info = { - records: 0 + records: 0, }; const api = stringifier(options, state, info); - for(const record of records){ - const err = api.__transform(record, function(record){ + for (const record of records) { + const err = api.__transform(record, function (record) { data.push(record); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - if(data.length === 0){ + if (data.length === 0) { api.bom((d) => { data.push(d); }); const err = api.headers((headers) => { data.push(headers); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - return data.join(''); + return data.join(""); }; export { stringify }; diff --git a/packages/csv-stringify/dist/iife/index.js b/packages/csv-stringify/dist/iife/index.js index deaab62ea..3422b3132 100644 --- a/packages/csv-stringify/dist/iife/index.js +++ b/packages/csv-stringify/dist/iife/index.js @@ -31,7 +31,7 @@ var csv_stringify = (function (exports) { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5129,136 +5129,163 @@ var csv_stringify = (function (exports) { class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; // Lodash implementation of `get` - const charCodeOfDot = '.'.charCodeAt(0); + const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", + ); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; - const getTag = function(value){ + const getTag = function (value) { return Object.prototype.toString.call(value); }; - const isSymbol = function(value){ + const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; - const isKey = function(value, object){ - if(Array.isArray(value)){ + const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; - const stringToPath = function(string){ + const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; - const castPath = function(value, object){ - if(Array.isArray(value)){ + const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; - const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; + const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; - const get = function(object, path){ + const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; - const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ + const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -5266,238 +5293,288 @@ var csv_stringify = (function (exports) { return [undefined, columns]; }; - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts) { + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer(options.escape)){ + } else if (isBuffer(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); - const stringifier = function(options, state, info){ + const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -5506,96 +5583,136 @@ var csv_stringify = (function (exports) { this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -5605,171 +5722,190 @@ var csv_stringify = (function (exports) { // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; + /* + CSV Stringify + + Please look at the [project documentation](https://csv.js.org/stringify/) for + additional information. + */ + + class Stringifier extends Transform { - constructor(opts = {}){ - super({...{writableObjectMode: true}, ...opts}); + constructor(opts = {}) { + super({ ...{ writableObjectMode: true }, ...opts }); const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; // Expose options this.options = options; // Internal state this.state = { - stop: false + stop: false, }; // Information this.info = { - records: 0 + records: 0, }; this.api = stringifier(this.options, this.state, this.info); this.api.options.on_record = (...args) => { - this.emit('record', ...args); + this.emit("record", ...args); }; } - _transform(chunk, encoding, callback){ - if(this.state.stop === true){ + _transform(chunk, encoding, callback) { + if (this.state.stop === true) { return; } const err = this.api.__transform(chunk, this.push.bind(this)); - if(err !== undefined){ + if (err !== undefined) { this.state.stop = true; } callback(err); } - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { // Note, Node.js 12 call flush even after an error, we must prevent // `callback` from being called in flush without any error. return; } - if(this.info.records === 0){ + if (this.info.records === 0) { this.api.bom(this.push.bind(this)); const err = this.api.headers(this.push.bind(this)); - if(err) callback(err); + if (err) callback(err); } callback(); } } - const stringify = function(){ + const stringify = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (Array.isArray(argument))){ + if (data === undefined && Array.isArray(argument)) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` + } else { + throw new CsvError("CSV_INVALID_ARGUMENT", [ + "Invalid argument:", + `got ${JSON.stringify(argument)} at index ${i}`, ]); } } const stringifier = new Stringifier(options); - if(callback){ + if (callback) { const chunks = []; - stringifier.on('readable', function(){ + stringifier.on("readable", function () { let chunk; - while((chunk = this.read()) !== null){ + while ((chunk = this.read()) !== null) { chunks.push(chunk); } }); - stringifier.on('error', function(err){ + stringifier.on("error", function (err) { callback(err); }); - stringifier.on('end', function(){ + stringifier.on("end", function () { try { - callback(undefined, chunks.join('')); + callback(undefined, chunks.join("")); } catch (err) { // This can happen if the `chunks` is extremely long; it may throw // "Cannot create a string longer than 0x1fffffe8 characters" @@ -5779,17 +5915,17 @@ var csv_stringify = (function (exports) { } }); } - if(data !== undefined){ - const writer = function(){ - for(const record of data){ + if (data !== undefined) { + const writer = function () { + for (const record of data) { stringifier.write(record); } stringifier.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv-stringify/dist/iife/sync.js b/packages/csv-stringify/dist/iife/sync.js index b4055f107..561cec219 100644 --- a/packages/csv-stringify/dist/iife/sync.js +++ b/packages/csv-stringify/dist/iife/sync.js @@ -1975,119 +1975,142 @@ var csv_stringify_sync = (function (exports) { // Lodash implementation of `get` - const charCodeOfDot = '.'.charCodeAt(0); + const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", + ); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; - const getTag = function(value){ + const getTag = function (value) { return Object.prototype.toString.call(value); }; - const isSymbol = function(value){ + const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; - const isKey = function(value, object){ - if(Array.isArray(value)){ + const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; - const stringToPath = function(string){ + const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; - const castPath = function(value, object){ - if(Array.isArray(value)){ + const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; - const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; + const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; - const get = function(object, path){ + const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; - const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; - const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ + const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -2097,253 +2120,307 @@ var csv_stringify_sync = (function (exports) { class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts) { + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer(options.escape)){ + } else if (isBuffer(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); - const stringifier = function(options, state, info){ + const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -2352,96 +2429,136 @@ var csv_stringify_sync = (function (exports) { this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -2451,121 +2568,132 @@ var csv_stringify_sync = (function (exports) { // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; - const stringify = function(records, opts={}){ + const stringify = function (records, opts = {}) { const data = []; const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; const state = { - stop: false + stop: false, }; // Information const info = { - records: 0 + records: 0, }; const api = stringifier(options, state, info); - for(const record of records){ - const err = api.__transform(record, function(record){ + for (const record of records) { + const err = api.__transform(record, function (record) { data.push(record); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - if(data.length === 0){ + if (data.length === 0) { api.bom((d) => { data.push(d); }); const err = api.headers((headers) => { data.push(headers); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - return data.join(''); + return data.join(""); }; exports.stringify = stringify; diff --git a/packages/csv-stringify/dist/umd/index.js b/packages/csv-stringify/dist/umd/index.js index e57967d55..c42f38295 100644 --- a/packages/csv-stringify/dist/umd/index.js +++ b/packages/csv-stringify/dist/umd/index.js @@ -34,7 +34,7 @@ this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5132,136 +5132,163 @@ class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; // Lodash implementation of `get` - const charCodeOfDot = '.'.charCodeAt(0); + const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", + ); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; - const getTag = function(value){ + const getTag = function (value) { return Object.prototype.toString.call(value); }; - const isSymbol = function(value){ + const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; - const isKey = function(value, object){ - if(Array.isArray(value)){ + const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; - const stringToPath = function(string){ + const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; - const castPath = function(value, object){ - if(Array.isArray(value)){ + const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; - const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; + const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; - const get = function(object, path){ + const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; - const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ + const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -5269,238 +5296,288 @@ return [undefined, columns]; }; - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts) { + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer(options.escape)){ + } else if (isBuffer(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); - const stringifier = function(options, state, info){ + const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -5509,96 +5586,136 @@ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -5608,171 +5725,190 @@ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; + /* + CSV Stringify + + Please look at the [project documentation](https://csv.js.org/stringify/) for + additional information. + */ + + class Stringifier extends Transform { - constructor(opts = {}){ - super({...{writableObjectMode: true}, ...opts}); + constructor(opts = {}) { + super({ ...{ writableObjectMode: true }, ...opts }); const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; // Expose options this.options = options; // Internal state this.state = { - stop: false + stop: false, }; // Information this.info = { - records: 0 + records: 0, }; this.api = stringifier(this.options, this.state, this.info); this.api.options.on_record = (...args) => { - this.emit('record', ...args); + this.emit("record", ...args); }; } - _transform(chunk, encoding, callback){ - if(this.state.stop === true){ + _transform(chunk, encoding, callback) { + if (this.state.stop === true) { return; } const err = this.api.__transform(chunk, this.push.bind(this)); - if(err !== undefined){ + if (err !== undefined) { this.state.stop = true; } callback(err); } - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { // Note, Node.js 12 call flush even after an error, we must prevent // `callback` from being called in flush without any error. return; } - if(this.info.records === 0){ + if (this.info.records === 0) { this.api.bom(this.push.bind(this)); const err = this.api.headers(this.push.bind(this)); - if(err) callback(err); + if (err) callback(err); } callback(); } } - const stringify = function(){ + const stringify = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (Array.isArray(argument))){ + if (data === undefined && Array.isArray(argument)) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` + } else { + throw new CsvError("CSV_INVALID_ARGUMENT", [ + "Invalid argument:", + `got ${JSON.stringify(argument)} at index ${i}`, ]); } } const stringifier = new Stringifier(options); - if(callback){ + if (callback) { const chunks = []; - stringifier.on('readable', function(){ + stringifier.on("readable", function () { let chunk; - while((chunk = this.read()) !== null){ + while ((chunk = this.read()) !== null) { chunks.push(chunk); } }); - stringifier.on('error', function(err){ + stringifier.on("error", function (err) { callback(err); }); - stringifier.on('end', function(){ + stringifier.on("end", function () { try { - callback(undefined, chunks.join('')); + callback(undefined, chunks.join("")); } catch (err) { // This can happen if the `chunks` is extremely long; it may throw // "Cannot create a string longer than 0x1fffffe8 characters" @@ -5782,17 +5918,17 @@ } }); } - if(data !== undefined){ - const writer = function(){ - for(const record of data){ + if (data !== undefined) { + const writer = function () { + for (const record of data) { stringifier.write(record); } stringifier.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv-stringify/dist/umd/sync.js b/packages/csv-stringify/dist/umd/sync.js index ad6a515b5..1b0149378 100644 --- a/packages/csv-stringify/dist/umd/sync.js +++ b/packages/csv-stringify/dist/umd/sync.js @@ -1978,119 +1978,142 @@ // Lodash implementation of `get` - const charCodeOfDot = '.'.charCodeAt(0); + const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", + ); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; - const getTag = function(value){ + const getTag = function (value) { return Object.prototype.toString.call(value); }; - const isSymbol = function(value){ + const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; - const isKey = function(value, object){ - if(Array.isArray(value)){ + const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; - const stringToPath = function(string){ + const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; - const castPath = function(value, object){ - if(Array.isArray(value)){ + const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; - const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; + const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; - const get = function(object, path){ + const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; - const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; - const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ + const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -2100,253 +2123,307 @@ class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts) { + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer(options.escape)){ + } else if (isBuffer(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); - const stringifier = function(options, state, info){ + const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -2355,96 +2432,136 @@ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -2454,121 +2571,132 @@ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; - const stringify = function(records, opts={}){ + const stringify = function (records, opts = {}) { const data = []; const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; const state = { - stop: false + stop: false, }; // Information const info = { - records: 0 + records: 0, }; const api = stringifier(options, state, info); - for(const record of records){ - const err = api.__transform(record, function(record){ + for (const record of records) { + const err = api.__transform(record, function (record) { data.push(record); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - if(data.length === 0){ + if (data.length === 0) { api.bom((d) => { data.push(d); }); const err = api.headers((headers) => { data.push(headers); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - return data.join(''); + return data.join(""); }; exports.stringify = stringify; diff --git a/packages/csv-stringify/eslint.config.js b/packages/csv-stringify/eslint.config.js new file mode 100644 index 000000000..c129c277f --- /dev/null +++ b/packages/csv-stringify/eslint.config.js @@ -0,0 +1,16 @@ +import globals from "globals"; +import js from "@eslint/js"; +import mocha from "eslint-plugin-mocha"; +import prettier from "eslint-plugin-prettier/recommended"; + +export default [ + { + ignores: ["dist/**"], + }, + { + languageOptions: { globals: { ...globals.node } }, + }, + js.configs.recommended, + mocha.configs.flat.recommended, + prettier, +]; diff --git a/packages/csv-stringify/lib/api/CsvError.js b/packages/csv-stringify/lib/api/CsvError.js index 5725c7d27..3af840a58 100644 --- a/packages/csv-stringify/lib/api/CsvError.js +++ b/packages/csv-stringify/lib/api/CsvError.js @@ -1,16 +1,19 @@ - class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = Buffer.isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = Buffer.isBuffer(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } diff --git a/packages/csv-stringify/lib/api/index.js b/packages/csv-stringify/lib/api/index.js index 2bd65f6a7..3d1a7115a 100644 --- a/packages/csv-stringify/lib/api/index.js +++ b/packages/csv-stringify/lib/api/index.js @@ -1,64 +1,70 @@ - -import { get } from '../utils/get.js'; -import { is_object } from '../utils/is_object.js'; -import { normalize_columns } from './normalize_columns.js'; -import { normalize_options } from './normalize_options.js'; +import { get } from "../utils/get.js"; +import { is_object } from "../utils/is_object.js"; +import { normalize_columns } from "./normalize_columns.js"; +import { normalize_options } from "./normalize_options.js"; const bom_utf8 = Buffer.from([239, 187, 191]); -const stringifier = function(options, state, info){ +const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else{ + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else{ + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else{ - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -67,96 +73,136 @@ const stringifier = function(options, state, info){ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else{ - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else{ - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -166,91 +212,102 @@ const stringifier = function(options, state, info){ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else{ + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else{ + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; -export {stringifier}; +export { stringifier }; diff --git a/packages/csv-stringify/lib/api/normalize_columns.js b/packages/csv-stringify/lib/api/normalize_columns.js index f9a177e66..53e4b2700 100644 --- a/packages/csv-stringify/lib/api/normalize_columns.js +++ b/packages/csv-stringify/lib/api/normalize_columns.js @@ -1,38 +1,45 @@ - -const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ +const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else{ + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else{ - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -40,4 +47,4 @@ const normalize_columns = function(columns){ return [undefined, columns]; }; -export {normalize_columns}; +export { normalize_columns }; diff --git a/packages/csv-stringify/lib/api/normalize_options.js b/packages/csv-stringify/lib/api/normalize_options.js index 2b92375b8..b7cb5d394 100644 --- a/packages/csv-stringify/lib/api/normalize_options.js +++ b/packages/csv-stringify/lib/api/normalize_options.js @@ -1,190 +1,232 @@ +import { CsvError } from "./CsvError.js"; +import { normalize_columns } from "./normalize_columns.js"; +import { underscore } from "../utils/underscore.js"; -import { CsvError } from './CsvError.js'; -import { normalize_columns } from './normalize_columns.js'; -import { underscore } from '../utils/underscore.js'; - -const normalize_options = function(opts) { +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(Buffer.isBuffer(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (Buffer.isBuffer(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (Buffer.isBuffer(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (Buffer.isBuffer(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; - }else{ + } else { // todo } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; - }else{ + } else { // todo } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; - }else{ + } else { // todo } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; - }else{ + } else { // todo } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(Buffer.isBuffer(options.escape)){ + } else if (Buffer.isBuffer(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; - }else{ + } else { // todo } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; - }else{ + } else { // todo } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; - }else{ + } else { // todo } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(Buffer.isBuffer(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (Buffer.isBuffer(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; -export {normalize_options}; +export { normalize_options }; diff --git a/packages/csv-stringify/lib/index.js b/packages/csv-stringify/lib/index.js index 81a9cc7d7..3ebb5f781 100644 --- a/packages/csv-stringify/lib/index.js +++ b/packages/csv-stringify/lib/index.js @@ -1,4 +1,3 @@ - /* CSV Stringify @@ -6,90 +5,90 @@ Please look at the [project documentation](https://csv.js.org/stringify/) for additional information. */ -import { Transform } from 'stream'; -import { CsvError } from './api/CsvError.js'; -import { is_object } from './utils/is_object.js'; -import { stringifier } from './api/index.js'; -import { normalize_options } from './api/normalize_options.js'; +import { Transform } from "stream"; +import { CsvError } from "./api/CsvError.js"; +import { is_object } from "./utils/is_object.js"; +import { stringifier } from "./api/index.js"; +import { normalize_options } from "./api/normalize_options.js"; class Stringifier extends Transform { - constructor(opts = {}){ - super({...{writableObjectMode: true}, ...opts}); + constructor(opts = {}) { + super({ ...{ writableObjectMode: true }, ...opts }); const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; // Expose options this.options = options; // Internal state this.state = { - stop: false + stop: false, }; // Information this.info = { - records: 0 + records: 0, }; this.api = stringifier(this.options, this.state, this.info); this.api.options.on_record = (...args) => { - this.emit('record', ...args); + this.emit("record", ...args); }; } - _transform(chunk, encoding, callback){ - if(this.state.stop === true){ + _transform(chunk, encoding, callback) { + if (this.state.stop === true) { return; } const err = this.api.__transform(chunk, this.push.bind(this)); - if(err !== undefined){ + if (err !== undefined) { this.state.stop = true; } callback(err); } - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { // Note, Node.js 12 call flush even after an error, we must prevent // `callback` from being called in flush without any error. return; } - if(this.info.records === 0){ + if (this.info.records === 0) { this.api.bom(this.push.bind(this)); const err = this.api.headers(this.push.bind(this)); - if(err) callback(err); + if (err) callback(err); } callback(); } } -const stringify = function(){ +const stringify = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (Array.isArray(argument))){ + if (data === undefined && Array.isArray(argument)) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else{ - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` + } else { + throw new CsvError("CSV_INVALID_ARGUMENT", [ + "Invalid argument:", + `got ${JSON.stringify(argument)} at index ${i}`, ]); } } const stringifier = new Stringifier(options); - if(callback){ + if (callback) { const chunks = []; - stringifier.on('readable', function(){ + stringifier.on("readable", function () { let chunk; - while((chunk = this.read()) !== null){ + while ((chunk = this.read()) !== null) { chunks.push(chunk); } }); - stringifier.on('error', function(err){ + stringifier.on("error", function (err) { callback(err); }); - stringifier.on('end', function(){ + stringifier.on("end", function () { try { - callback(undefined, chunks.join('')); + callback(undefined, chunks.join("")); } catch (err) { // This can happen if the `chunks` is extremely long; it may throw // "Cannot create a string longer than 0x1fffffe8 characters" @@ -99,17 +98,17 @@ const stringify = function(){ } }); } - if(data !== undefined){ - const writer = function(){ - for(const record of data){ + if (data !== undefined) { + const writer = function () { + for (const record of data) { stringifier.write(record); } stringifier.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else{ + } else { setTimeout(writer, 0); } } diff --git a/packages/csv-stringify/lib/sync.js b/packages/csv-stringify/lib/sync.js index 8c8cb9d65..6ae6d0b24 100644 --- a/packages/csv-stringify/lib/sync.js +++ b/packages/csv-stringify/lib/sync.js @@ -1,35 +1,34 @@ +import { stringifier } from "./api/index.js"; +import { normalize_options } from "./api/normalize_options.js"; -import { stringifier } from './api/index.js'; -import { normalize_options } from './api/normalize_options.js'; - -const stringify = function(records, opts={}){ +const stringify = function (records, opts = {}) { const data = []; const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; const state = { - stop: false + stop: false, }; // Information const info = { - records: 0 + records: 0, }; const api = stringifier(options, state, info); - for(const record of records){ - const err = api.__transform(record, function(record){ + for (const record of records) { + const err = api.__transform(record, function (record) { data.push(record); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - if(data.length === 0){ + if (data.length === 0) { api.bom((d) => { data.push(d); }); const err = api.headers((headers) => { data.push(headers); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - return data.join(''); + return data.join(""); }; export { stringify }; diff --git a/packages/csv-stringify/lib/utils/get.js b/packages/csv-stringify/lib/utils/get.js index 5dd9effaa..9513e8ba0 100644 --- a/packages/csv-stringify/lib/utils/get.js +++ b/packages/csv-stringify/lib/utils/get.js @@ -1,82 +1,94 @@ - - // Lodash implementation of `get` -const charCodeOfDot = '.'.charCodeAt(0); +const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", +); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; -const getTag = function(value){ - if(!value) - value === undefined ? '[object Undefined]' : '[object Null]'; +const getTag = function (value) { + if (!value) value === undefined ? "[object Undefined]" : "[object Null]"; return Object.prototype.toString.call(value); }; -const isSymbol = function(value){ +const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; -const isKey = function(value, object){ - if(Array.isArray(value)){ +const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; -const stringToPath = function(string){ +const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; -const castPath = function(value, object){ - if(Array.isArray(value)){ +const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; -const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; +const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; -const get = function(object, path){ +const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; -export {get}; +export { get }; diff --git a/packages/csv-stringify/lib/utils/is_object.js b/packages/csv-stringify/lib/utils/is_object.js index 13c243bc6..d8b70e248 100644 --- a/packages/csv-stringify/lib/utils/is_object.js +++ b/packages/csv-stringify/lib/utils/is_object.js @@ -1,7 +1,5 @@ - - -const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; -export {is_object}; +export { is_object }; diff --git a/packages/csv-stringify/lib/utils/underscore.js b/packages/csv-stringify/lib/utils/underscore.js index 78397a32e..6281e0096 100644 --- a/packages/csv-stringify/lib/utils/underscore.js +++ b/packages/csv-stringify/lib/utils/underscore.js @@ -1,8 +1,6 @@ - - -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; diff --git a/packages/csv-stringify/package.json b/packages/csv-stringify/package.json index 5710e6285..83d095078 100644 --- a/packages/csv-stringify/package.json +++ b/packages/csv-stringify/package.json @@ -11,14 +11,17 @@ ], "author": "David Worms (https://www.adaltas.com)", "devDependencies": { - "@rollup/plugin-eslint": "^9.0.5", + "@eslint/js": "^9.9.1", "@rollup/plugin-node-resolve": "^15.2.3", "@types/mocha": "^10.0.7", "@types/node": "^22.5.0", "coffeescript": "~2.7.0", "csv-generate": "^4.4.1", - "eslint": "^8.47.0", "each": "^2.7.0", + "eslint": "^9.9.1", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-mocha": "^10.5.0", + "eslint-plugin-prettier": "^5.2.1", "express": "^4.19.2", "mocha": "~10.7.3", "prettier": "^3.3.3", @@ -87,11 +90,8 @@ "build:rollup": "npx rollup -c", "build:ts": "cp lib/index.d.ts dist/cjs/index.d.cts && cp lib/sync.d.ts dist/cjs/sync.d.cts && cp lib/*.ts dist/esm", "postbuild:ts": "find dist/cjs -name '*.d.cts' -exec sh -c \"sed -i \"s/\\.js'/\\.cjs'/g\" {} || sed -i '' \"s/\\.js'/\\.cjs'/g\" {}\" \\;", - "lint": "npm run lint:lib && npm run lint:samples && npm run lint:test", - "postlint": "tsc --noEmit true", - "lint:lib": "eslint --fix lib/*.js", - "lint:samples": "eslint --fix samples/*.js", - "lint:test": "coffeelint --fix test/*.coffee", + "lint:check": "eslint && tsc --noEmit true", + "lint:fix": "eslint --fix && tsc --noEmit true", "preversion": "npm run build && git add dist", "pretest": "npm run build", "test": "mocha 'test/**/*.{coffee,ts}'", diff --git a/packages/csv-stringify/rollup.config.js b/packages/csv-stringify/rollup.config.js index ba5136784..b751c9530 100644 --- a/packages/csv-stringify/rollup.config.js +++ b/packages/csv-stringify/rollup.config.js @@ -1,82 +1,102 @@ +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import globals from "rollup-plugin-node-globals"; +import builtins from "rollup-plugin-node-builtins"; +// import eslint from "@rollup/plugin-eslint"; -import { nodeResolve } from '@rollup/plugin-node-resolve'; -import globals from 'rollup-plugin-node-globals'; -import builtins from 'rollup-plugin-node-builtins'; -import eslint from '@rollup/plugin-eslint'; - -export default [{ - onwarn: function(warning, rollupWarn) { - // Not much we can do, Node.js `readable-stream/readable.js` and - // `readable-stream/duplex.js` from `rollup-plugin-node-builtins` raise this - // issue. - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - rollupWarn(warning); - }, - input: 'lib/index.js', - output: [ - { - file: `dist/esm/index.js`, - format: 'esm' - }, - { - file: `dist/iife/index.js`, - format: 'iife', - name: 'csv_stringify' +export default [ + { + onwarn: function (warning, rollupWarn) { + // Not much we can do, Node.js `readable-stream/readable.js` and + // `readable-stream/duplex.js` from `rollup-plugin-node-builtins` raise this + // issue. + if (warning.code === "CIRCULAR_DEPENDENCY") return; + rollupWarn(warning); }, - { - file: `dist/umd/index.js`, - format: 'umd', - name: 'csv_stringify' - }, - ], - plugins: [eslint({ - fix: true, - }), globals(), builtins(), nodeResolve()], -}, { - input: 'lib/index.js', - output: [ - { - file: `dist/cjs/index.cjs`, - format: 'cjs' - }, - ], - plugins: [eslint({ - fix: true, - }), nodeResolve()], -}, { - onwarn: function(warning, rollupWarn) { - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - rollupWarn(warning); + input: "lib/index.js", + output: [ + { + file: `dist/esm/index.js`, + format: "esm", + }, + { + file: `dist/iife/index.js`, + format: "iife", + name: "csv_stringify", + }, + { + file: `dist/umd/index.js`, + format: "umd", + name: "csv_stringify", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + globals(), + builtins(), + nodeResolve(), + ], }, - input: 'lib/sync.js', - output: [ - { - file: `dist/esm/sync.js`, - format: 'esm' - }, - { - file: `dist/iife/sync.js`, - format: 'iife', - name: 'csv_stringify_sync' - }, - { - file: `dist/umd/sync.js`, - format: 'umd', - name: 'csv_stringify_sync' - }, - ], - plugins: [eslint({ - fix: true, - }), globals(), builtins(), nodeResolve()], -}, { - input: 'lib/sync.js', - output: [ - { - file: `dist/cjs/sync.cjs`, - format: 'cjs' + { + input: "lib/index.js", + output: [ + { + file: `dist/cjs/index.cjs`, + format: "cjs", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + nodeResolve(), + ], + }, + { + onwarn: function (warning, rollupWarn) { + if (warning.code === "CIRCULAR_DEPENDENCY") return; + rollupWarn(warning); }, - ], - plugins: [eslint({ - fix: true, - }), nodeResolve()], -}]; + input: "lib/sync.js", + output: [ + { + file: `dist/esm/sync.js`, + format: "esm", + }, + { + file: `dist/iife/sync.js`, + format: "iife", + name: "csv_stringify_sync", + }, + { + file: `dist/umd/sync.js`, + format: "umd", + name: "csv_stringify_sync", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + globals(), + builtins(), + nodeResolve(), + ], + }, + { + input: "lib/sync.js", + output: [ + { + file: `dist/cjs/sync.cjs`, + format: "cjs", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + nodeResolve(), + ], + }, +]; diff --git a/packages/csv-stringify/samples/api.async.iterator.js b/packages/csv-stringify/samples/api.async.iterator.js index f6f9339fc..c339f6398 100644 --- a/packages/csv-stringify/samples/api.async.iterator.js +++ b/packages/csv-stringify/samples/api.async.iterator.js @@ -1,5 +1,4 @@ - -import assert from 'node:assert'; +import assert from "node:assert"; import { generate } from "csv-generate"; import { stringify } from "csv-stringify"; @@ -8,9 +7,11 @@ const stringifier = generate({ length: 1000, objectMode: true, seed: true, -}).pipe(stringify({ - readableHighWaterMark: 15000 -})); +}).pipe( + stringify({ + readableHighWaterMark: 15000, + }), +); // Count records let count = 0; // Report start diff --git a/packages/csv-stringify/samples/api.callback.js b/packages/csv-stringify/samples/api.callback.js index 42b4542a1..ccf402cb7 100644 --- a/packages/csv-stringify/samples/api.callback.js +++ b/packages/csv-stringify/samples/api.callback.js @@ -1,10 +1,12 @@ +import assert from "node:assert"; +import { stringify } from "csv-stringify"; -import assert from 'node:assert'; -import { stringify } from 'csv-stringify'; - -stringify([ - [ '1', '2', '3', '4' ], - [ 'a', 'b', 'c', 'd' ] -], function(err, output){ - assert.equal(output, '1,2,3,4\na,b,c,d\n'); -}); +stringify( + [ + ["1", "2", "3", "4"], + ["a", "b", "c", "d"], + ], + function (err, output) { + assert.equal(output, "1,2,3,4\na,b,c,d\n"); + }, +); diff --git a/packages/csv-stringify/samples/api.pipe.js b/packages/csv-stringify/samples/api.pipe.js index 2106841a8..914a93d70 100644 --- a/packages/csv-stringify/samples/api.pipe.js +++ b/packages/csv-stringify/samples/api.pipe.js @@ -1,19 +1,20 @@ - -import { stringify } from 'csv-stringify'; -import { generate } from 'csv-generate'; +import { stringify } from "csv-stringify"; +import { generate } from "csv-generate"; generate({ length: 20, objectMode: true, seed: 1, headers: 2, - duration: 400 + duration: 400, }) - .pipe(stringify({ - header: true, - columns: { - year: 'birthYear', - phone: 'phone' - } - })) + .pipe( + stringify({ + header: true, + columns: { + year: "birthYear", + phone: "phone", + }, + }), + ) .pipe(process.stdout); diff --git a/packages/csv-stringify/samples/api.stream.js b/packages/csv-stringify/samples/api.stream.js index 6ced13584..b96c30dd2 100644 --- a/packages/csv-stringify/samples/api.stream.js +++ b/packages/csv-stringify/samples/api.stream.js @@ -1,33 +1,40 @@ - -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; +import { stringify } from "csv-stringify"; +import assert from "node:assert"; const data = []; // Initialize the stringifier const stringifier = stringify({ - delimiter: ':' + delimiter: ":", }); // Use the readable stream api to consume CSV data -stringifier.on('readable', function(){ +stringifier.on("readable", function () { let row; - while((row = stringifier.read()) !== null){ + while ((row = stringifier.read()) !== null) { data.push(row); } }); // Catch any error -stringifier.on('error', function(err){ +stringifier.on("error", function (err) { console.error(err.message); }); // When finished, validate the CSV output with the expected value -stringifier.on('finish', function(){ +stringifier.on("finish", function () { assert.equal( - data.join(''), - 'root:x:0:0:root:/root:/bin/bash\n' + - 'someone:x:1022:1022::/home/someone:/bin/bash\n' + data.join(""), + "root:x:0:0:root:/root:/bin/bash\n" + + "someone:x:1022:1022::/home/someone:/bin/bash\n", ); }); // Write records to the stream -stringifier.write([ 'root','x','0','0','root','/root','/bin/bash' ]); -stringifier.write([ 'someone','x','1022','1022','','/home/someone','/bin/bash' ]); +stringifier.write(["root", "x", "0", "0", "root", "/root", "/bin/bash"]); +stringifier.write([ + "someone", + "x", + "1022", + "1022", + "", + "/home/someone", + "/bin/bash", +]); // Close the writable stream stringifier.end(); diff --git a/packages/csv-stringify/samples/api.sync.js b/packages/csv-stringify/samples/api.sync.js index 30d5322fc..41e199cda 100644 --- a/packages/csv-stringify/samples/api.sync.js +++ b/packages/csv-stringify/samples/api.sync.js @@ -1,10 +1,9 @@ - -import { stringify } from 'csv-stringify/sync'; -import assert from 'node:assert'; +import { stringify } from "csv-stringify/sync"; +import assert from "node:assert"; const output = stringify([ - [ '1', '2', '3', '4' ], - [ 'a', 'b', 'c', 'd' ] + ["1", "2", "3", "4"], + ["a", "b", "c", "d"], ]); -assert.equal(output, '1,2,3,4\na,b,c,d\n'); +assert.equal(output, "1,2,3,4\na,b,c,d\n"); diff --git a/packages/csv-stringify/samples/api.sync.memory.js b/packages/csv-stringify/samples/api.sync.memory.js index b65e7bec8..ce07bf4d7 100644 --- a/packages/csv-stringify/samples/api.sync.memory.js +++ b/packages/csv-stringify/samples/api.sync.memory.js @@ -1,22 +1,29 @@ +import { stringify } from "csv-stringify/sync"; -import { stringify } from 'csv-stringify/sync'; - -const r = v => (v / 1024 / 1024).toFixed(2); +const r = (v) => (v / 1024 / 1024).toFixed(2); const printMemoryUsage = () => { const { rss, heapTotal, heapUsed } = process.memoryUsage(); - console.log(`Memory usage: rss ${r(rss)}, heap ${r(heapUsed)} / ${r(heapTotal)}`); + console.log( + `Memory usage: rss ${r(rss)}, heap ${r(heapUsed)} / ${r(heapTotal)}`, + ); }; const attempts = 3; // Increase if necessary -const record = []; for (let i = 0; i < 100; i += 1) { record.push(`field-${i}`); } -const records = []; for (let i = 0; i < 100000; i += 1) { records.push([...record]); } +const record = []; +for (let i = 0; i < 100; i += 1) { + record.push(`field-${i}`); +} +const records = []; +for (let i = 0; i < 100000; i += 1) { + records.push([...record]); +} -console.log(': records created'); +console.log(": records created"); printMemoryUsage(); for (let i = 1; i < attempts; i += 1) { stringify(records); - console.log(': after stringify # %s', i); + console.log(": after stringify # %s", i); printMemoryUsage(); } diff --git a/packages/csv-stringify/samples/browser/index.js b/packages/csv-stringify/samples/browser/index.js index f4f701cdd..72c52eb7f 100644 --- a/packages/csv-stringify/samples/browser/index.js +++ b/packages/csv-stringify/samples/browser/index.js @@ -1,11 +1,10 @@ +const express = require("express"); +const app = express(); +const port = 3000; -const express = require('express') -const app = express() -const port = 3000 - -app.use(express.static(__dirname)) -app.use('/lib', express.static(`${__dirname}/../../lib/browser`)) +app.use(express.static(__dirname)); +app.use("/lib", express.static(`${__dirname}/../../lib/browser`)); app.listen(port, () => { - console.log(`Example app listening at http://localhost:${port}`) -}) + console.log(`Example app listening at http://localhost:${port}`); +}); diff --git a/packages/csv-stringify/samples/mixed.input_stream.js b/packages/csv-stringify/samples/mixed.input_stream.js index 2270ea6c3..feef78fde 100644 --- a/packages/csv-stringify/samples/mixed.input_stream.js +++ b/packages/csv-stringify/samples/mixed.input_stream.js @@ -1,19 +1,29 @@ - -import assert from 'node:assert'; -import { stringify } from 'csv-stringify'; +import assert from "node:assert"; +import { stringify } from "csv-stringify"; // Create the parser -const stringifier = stringify({ - delimiter: ':' -}, function(err, data){ - assert.deepStrictEqual( - data, - 'root:x:0:0:root:/root:/bin/bash\n' + - 'someone:x:1022:1022::/home/someone:/bin/bash\n' - ); -}); +const stringifier = stringify( + { + delimiter: ":", + }, + function (err, data) { + assert.deepStrictEqual( + data, + "root:x:0:0:root:/root:/bin/bash\n" + + "someone:x:1022:1022::/home/someone:/bin/bash\n", + ); + }, +); // Write records to the stream -stringifier.write([ 'root','x','0','0','root','/root','/bin/bash' ]); -stringifier.write([ 'someone','x','1022','1022','','/home/someone','/bin/bash' ]); +stringifier.write(["root", "x", "0", "0", "root", "/root", "/bin/bash"]); +stringifier.write([ + "someone", + "x", + "1022", + "1022", + "", + "/home/someone", + "/bin/bash", +]); // Close the writable stream stringifier.end(); diff --git a/packages/csv-stringify/samples/mixed.output_stream.js b/packages/csv-stringify/samples/mixed.output_stream.js index 3ca123540..f713b9a0f 100644 --- a/packages/csv-stringify/samples/mixed.output_stream.js +++ b/packages/csv-stringify/samples/mixed.output_stream.js @@ -1,22 +1,19 @@ - -import assert from 'node:assert'; -import { stringify } from 'csv-stringify'; +import assert from "node:assert"; +import { stringify } from "csv-stringify"; const data = []; stringify([ - [ '1', '2', '3', '4' ], - [ 'a', 'b', 'c', 'd' ] + ["1", "2", "3", "4"], + ["a", "b", "c", "d"], ]) -// Use the readable stream api - .on('readable', function(){ - let row; while ((row = this.read()) !== null) { + // Use the readable stream api + .on("readable", function () { + let row; + while ((row = this.read()) !== null) { data.push(row); } }) -// When we are done, test that the parsed records matched what expected - .on('end', function(){ - assert.deepStrictEqual( - data.join(''), - '1,2,3,4\na,b,c,d\n' - ); + // When we are done, test that the parsed records matched what expected + .on("end", function () { + assert.deepStrictEqual(data.join(""), "1,2,3,4\na,b,c,d\n"); }); diff --git a/packages/csv-stringify/samples/option.bom.js b/packages/csv-stringify/samples/option.bom.js index 3cce8c491..e8077feb2 100644 --- a/packages/csv-stringify/samples/option.bom.js +++ b/packages/csv-stringify/samples/option.bom.js @@ -1,10 +1,7 @@ +import assert from "node:assert"; +import { stringify } from "csv-stringify/sync"; -import assert from 'node:assert'; -import { stringify } from 'csv-stringify/sync'; - -const data = stringify([ - [ 'a', 'b', 'c' ] -], { - bom: true +const data = stringify([["a", "b", "c"]], { + bom: true, }); -assert.deepStrictEqual(data, '\ufeffa,b,c\n'); +assert.deepStrictEqual(data, "\ufeffa,b,c\n"); diff --git a/packages/csv-stringify/samples/option.cast.date.js b/packages/csv-stringify/samples/option.cast.date.js index eb7783582..a373e2db4 100644 --- a/packages/csv-stringify/samples/option.cast.date.js +++ b/packages/csv-stringify/samples/option.cast.date.js @@ -1,23 +1,28 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([{ - name: 'foo', - date: new Date('1970-01-01T00:00:00.000Z') -},{ - name: 'bar', - date: new Date('1971-01-01T00:00:00.000Z') -}],{ - cast: { - date: function(value) { - return value.toISOString(); - } - } -}, function(err, data) { - assert.equal( - data, - 'foo,1970-01-01T00:00:00.000Z\n' + - 'bar,1971-01-01T00:00:00.000Z\n' - ); -}); +stringify( + [ + { + name: "foo", + date: new Date("1970-01-01T00:00:00.000Z"), + }, + { + name: "bar", + date: new Date("1971-01-01T00:00:00.000Z"), + }, + ], + { + cast: { + date: function (value) { + return value.toISOString(); + }, + }, + }, + function (err, data) { + assert.equal( + data, + "foo,1970-01-01T00:00:00.000Z\n" + "bar,1971-01-01T00:00:00.000Z\n", + ); + }, +); diff --git a/packages/csv-stringify/samples/option.cast.js b/packages/csv-stringify/samples/option.cast.js index dbc13606b..a6cff6600 100644 --- a/packages/csv-stringify/samples/option.cast.js +++ b/packages/csv-stringify/samples/option.cast.js @@ -1,13 +1,12 @@ +import assert from "node:assert"; +import { stringify } from "csv-stringify/sync"; -import assert from 'node:assert'; -import { stringify } from 'csv-stringify/sync'; - -const data = stringify([ [1], [2] ], { +const data = stringify([[1], [2]], { cast: { - number: function(value){ - return {value: `="${value}"`, quote: false}; - } - } + number: function (value) { + return { value: `="${value}"`, quote: false }; + }, + }, }); assert.equal(data, '="1"\n="2"\n'); diff --git a/packages/csv-stringify/samples/option.columns_array_with_objects.js b/packages/csv-stringify/samples/option.columns_array_with_objects.js index b8dedcac5..2d3c489a1 100644 --- a/packages/csv-stringify/samples/option.columns_array_with_objects.js +++ b/packages/csv-stringify/samples/option.columns_array_with_objects.js @@ -1,11 +1,12 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - { a: '1', b: '2' } -], { - columns: [ { key: 'a' }, { key: 'b' } ] -}, function(err, data){ - assert.equal(data, '1,2\n'); -}); +stringify( + [{ a: "1", b: "2" }], + { + columns: [{ key: "a" }, { key: "b" }], + }, + function (err, data) { + assert.equal(data, "1,2\n"); + }, +); diff --git a/packages/csv-stringify/samples/option.columns_array_with_strings.js b/packages/csv-stringify/samples/option.columns_array_with_strings.js index 1a8e555a7..9d2c5435d 100644 --- a/packages/csv-stringify/samples/option.columns_array_with_strings.js +++ b/packages/csv-stringify/samples/option.columns_array_with_strings.js @@ -1,11 +1,12 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - { a: '1', b: '2' } -], { - columns: [ 'a', 'b' ] -}, function(err, data){ - assert.equal(data, '1,2\n'); -}); +stringify( + [{ a: "1", b: "2" }], + { + columns: ["a", "b"], + }, + function (err, data) { + assert.equal(data, "1,2\n"); + }, +); diff --git a/packages/csv-stringify/samples/option.columns_nested.js b/packages/csv-stringify/samples/option.columns_nested.js index cc408e3b3..f42c9b28a 100644 --- a/packages/csv-stringify/samples/option.columns_nested.js +++ b/packages/csv-stringify/samples/option.columns_nested.js @@ -1,26 +1,33 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([{ - an_array: [{ - }, { - field_2: '1_val_1' - }], - an_object: { - field_4: '1_val_2' - } -},{ - an_array: [{ - }, { - field_2: '2_val_1' - }], - an_object: { - field_4: '2_val_2' - } -}], {columns: [ - 'an_object.field_4', - 'an_array[1].field_2' -]}, (err, records) => { - assert.equal(records, '1_val_2,1_val_1\n2_val_2,2_val_1\n'); -}); +stringify( + [ + { + an_array: [ + {}, + { + field_2: "1_val_1", + }, + ], + an_object: { + field_4: "1_val_2", + }, + }, + { + an_array: [ + {}, + { + field_2: "2_val_1", + }, + ], + an_object: { + field_4: "2_val_2", + }, + }, + ], + { columns: ["an_object.field_4", "an_array[1].field_2"] }, + (err, records) => { + assert.equal(records, "1_val_2,1_val_1\n2_val_2,2_val_1\n"); + }, +); diff --git a/packages/csv-stringify/samples/option.columns_undefined.js b/packages/csv-stringify/samples/option.columns_undefined.js index ef3dcc203..246e56a34 100644 --- a/packages/csv-stringify/samples/option.columns_undefined.js +++ b/packages/csv-stringify/samples/option.columns_undefined.js @@ -1,16 +1,15 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - { year: 'XXXX', phone: 'XXX XXXX', nocolumn: 'XXX' }, - { year: 'YYYY', phone: 'YYY YYYY', nocolumn: 'XXX' } -],{ - columns: ['phone', 'year', 'nofield'] -}, function(err, data){ - assert.equal( - data, - 'XXX XXXX,XXXX,\n' + - 'YYY YYYY,YYYY,\n' - ); -}); +stringify( + [ + { year: "XXXX", phone: "XXX XXXX", nocolumn: "XXX" }, + { year: "YYYY", phone: "YYY YYYY", nocolumn: "XXX" }, + ], + { + columns: ["phone", "year", "nofield"], + }, + function (err, data) { + assert.equal(data, "XXX XXXX,XXXX,\n" + "YYY YYYY,YYYY,\n"); + }, +); diff --git a/packages/csv-stringify/samples/option.delimiter_multiple.js b/packages/csv-stringify/samples/option.delimiter_multiple.js index 7d742436b..d74b07670 100644 --- a/packages/csv-stringify/samples/option.delimiter_multiple.js +++ b/packages/csv-stringify/samples/option.delimiter_multiple.js @@ -1,12 +1,15 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - ['1', '2'], - ['3', '4'] -], { - delimiter: ':)' -}, function(err, records){ - assert.equal(records, '1:)2\n3:)4\n'); -}); +stringify( + [ + ["1", "2"], + ["3", "4"], + ], + { + delimiter: ":)", + }, + function (err, records) { + assert.equal(records, "1:)2\n3:)4\n"); + }, +); diff --git a/packages/csv-stringify/samples/option.delimiter_single.js b/packages/csv-stringify/samples/option.delimiter_single.js index 1f29586c3..e1b9725b3 100644 --- a/packages/csv-stringify/samples/option.delimiter_single.js +++ b/packages/csv-stringify/samples/option.delimiter_single.js @@ -1,10 +1,12 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - ['1', '2'], - ['3', '4'] -], function(err, records){ - assert.equal(records, '1,2\n3,4\n'); -}); +stringify( + [ + ["1", "2"], + ["3", "4"], + ], + function (err, records) { + assert.equal(records, "1,2\n3,4\n"); + }, +); diff --git a/packages/csv-stringify/samples/option.eof_false.js b/packages/csv-stringify/samples/option.eof_false.js index 01253bef7..9ef05e66a 100644 --- a/packages/csv-stringify/samples/option.eof_false.js +++ b/packages/csv-stringify/samples/option.eof_false.js @@ -8,6 +8,6 @@ const data = stringify( ], { eof: false, - } + }, ); assert.deepStrictEqual(data, "a,b\nc,d"); diff --git a/packages/csv-stringify/samples/option.escape.custom.js b/packages/csv-stringify/samples/option.escape.custom.js index 26e6c9d60..853c48600 100644 --- a/packages/csv-stringify/samples/option.escape.custom.js +++ b/packages/csv-stringify/samples/option.escape.custom.js @@ -1,9 +1,6 @@ +import { stringify } from "csv-stringify/sync"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify/sync'; -import assert from 'node:assert'; - -const records = stringify([ - ['a "value"'], -], {escape: '\\'}); +const records = stringify([['a "value"']], { escape: "\\" }); assert.equal(records, '"a \\"value\\""\n'); diff --git a/packages/csv-stringify/samples/option.escape.default.js b/packages/csv-stringify/samples/option.escape.default.js index b50aa46e7..9b26b7360 100644 --- a/packages/csv-stringify/samples/option.escape.default.js +++ b/packages/csv-stringify/samples/option.escape.default.js @@ -1,9 +1,6 @@ +import { stringify } from "csv-stringify/sync"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify/sync'; -import assert from 'node:assert'; - -const records = stringify([ - ['a "value"'], -]); +const records = stringify([['a "value"']]); assert.equal(records, '"a ""value"""\n'); diff --git a/packages/csv-stringify/samples/option.escape_formulas.js b/packages/csv-stringify/samples/option.escape_formulas.js index 377908722..44e52da33 100644 --- a/packages/csv-stringify/samples/option.escape_formulas.js +++ b/packages/csv-stringify/samples/option.escape_formulas.js @@ -1,10 +1,12 @@ +import { stringify } from "csv-stringify/sync"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify/sync'; -import assert from 'node:assert'; - -const records = stringify([ - ['=1', '@2', '3'], - ['=4', '@5', '6'] -], {escape_formulas: true}); +const records = stringify( + [ + ["=1", "@2", "3"], + ["=4", "@5", "6"], + ], + { escape_formulas: true }, +); assert.equal(records, "'=1,'@2,3\n'=4,'@5,6\n"); diff --git a/packages/csv-stringify/samples/option.header.js b/packages/csv-stringify/samples/option.header.js index 3281fec4b..bac985a09 100644 --- a/packages/csv-stringify/samples/option.header.js +++ b/packages/csv-stringify/samples/option.header.js @@ -1,17 +1,15 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - { year: 'XXXX', phone: 'XXX XXXX' }, - { year: 'YYYY', phone: 'YYY YYYY' } -],{ - header: true -}, function(err, data){ - assert.equal( - data, - 'year,phone\n' + - 'XXXX,XXX XXXX\n' + - 'YYYY,YYY YYYY\n' - ); -}); +stringify( + [ + { year: "XXXX", phone: "XXX XXXX" }, + { year: "YYYY", phone: "YYY YYYY" }, + ], + { + header: true, + }, + function (err, data) { + assert.equal(data, "year,phone\n" + "XXXX,XXX XXXX\n" + "YYYY,YYY YYYY\n"); + }, +); diff --git a/packages/csv-stringify/samples/option.header_width_columns_object.js b/packages/csv-stringify/samples/option.header_width_columns_object.js index 66a6b5c44..4f16ace36 100644 --- a/packages/csv-stringify/samples/option.header_width_columns_object.js +++ b/packages/csv-stringify/samples/option.header_width_columns_object.js @@ -1,12 +1,13 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - { a: '1', b: '2' } -], { - header: true, - columns: { 'a': 'col_a', 'b': 'col_b' } -}, function(err, data){ - assert.equal(data, 'col_a,col_b\n1,2\n'); -}); +stringify( + [{ a: "1", b: "2" }], + { + header: true, + columns: { a: "col_a", b: "col_b" }, + }, + function (err, data) { + assert.equal(data, "col_a,col_b\n1,2\n"); + }, +); diff --git a/packages/csv-stringify/samples/option.header_with_columns_array_strings.js b/packages/csv-stringify/samples/option.header_with_columns_array_strings.js index 9490f28ca..d1b9e4baf 100644 --- a/packages/csv-stringify/samples/option.header_with_columns_array_strings.js +++ b/packages/csv-stringify/samples/option.header_with_columns_array_strings.js @@ -1,12 +1,16 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - { a: '1', b: '2' } -], { - header: true, - columns: [ { key: 'a', header: 'col_a' }, { key: 'b', header: 'col_b' } ] -}, function(err, data){ - assert.equal(data, 'col_a,col_b\n1,2\n'); -}); +stringify( + [{ a: "1", b: "2" }], + { + header: true, + columns: [ + { key: "a", header: "col_a" }, + { key: "b", header: "col_b" }, + ], + }, + function (err, data) { + assert.equal(data, "col_a,col_b\n1,2\n"); + }, +); diff --git a/packages/csv-stringify/samples/option.quote.custom.js b/packages/csv-stringify/samples/option.quote.custom.js index 40f18de44..1872c9dad 100644 --- a/packages/csv-stringify/samples/option.quote.custom.js +++ b/packages/csv-stringify/samples/option.quote.custom.js @@ -1,11 +1,8 @@ +import { stringify } from "csv-stringify/sync"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify/sync'; -import assert from 'node:assert'; - -const records = stringify([ - ['a,b'] -], { - quote: '|' +const records = stringify([["a,b"]], { + quote: "|", }); -assert.equal(records, '|a,b|\n'); +assert.equal(records, "|a,b|\n"); diff --git a/packages/csv-stringify/samples/option.quoted.js b/packages/csv-stringify/samples/option.quoted.js index 1eee17896..01667cf7c 100644 --- a/packages/csv-stringify/samples/option.quoted.js +++ b/packages/csv-stringify/samples/option.quoted.js @@ -1,14 +1,16 @@ +import { stringify } from "csv-stringify/sync"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify/sync'; -import assert from 'node:assert'; - -const records = stringify([ - ['1', ''], - [false, '2'], - ['3', null], - [undefined, '4'] -], { - quoted: true -}); +const records = stringify( + [ + ["1", ""], + [false, "2"], + ["3", null], + [undefined, "4"], + ], + { + quoted: true, + }, +); assert.equal(records, '"1",\n,"2"\n"3",\n,"4"\n'); diff --git a/packages/csv-stringify/samples/option.quoted_empty.js b/packages/csv-stringify/samples/option.quoted_empty.js index a550bcf79..a6f56fdec 100644 --- a/packages/csv-stringify/samples/option.quoted_empty.js +++ b/packages/csv-stringify/samples/option.quoted_empty.js @@ -1,14 +1,17 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - ['1', ''], - [false, '2'], - ['3', null], - [undefined, '4'] -], { - quoted_empty: true -}, function(err, records){ - assert.equal(records, '1,""\n"",2\n3,""\n"",4\n'); -}); +stringify( + [ + ["1", ""], + [false, "2"], + ["3", null], + [undefined, "4"], + ], + { + quoted_empty: true, + }, + function (err, records) { + assert.equal(records, '1,""\n"",2\n3,""\n"",4\n'); + }, +); diff --git a/packages/csv-stringify/samples/option.quoted_match_regexp.js b/packages/csv-stringify/samples/option.quoted_match_regexp.js index bf3178e85..9d6da24b1 100644 --- a/packages/csv-stringify/samples/option.quoted_match_regexp.js +++ b/packages/csv-stringify/samples/option.quoted_match_regexp.js @@ -1,11 +1,12 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - ['a value', '.', 'value.with.dot'], -], { - quoted_match: /\./ -}, function(err, records){ - assert.equal(records, 'a value,".","value.with.dot"\n'); -}); +stringify( + [["a value", ".", "value.with.dot"]], + { + quoted_match: /\./, + }, + function (err, records) { + assert.equal(records, 'a value,".","value.with.dot"\n'); + }, +); diff --git a/packages/csv-stringify/samples/option.quoted_match_string.js b/packages/csv-stringify/samples/option.quoted_match_string.js index bd5743fef..908a97060 100644 --- a/packages/csv-stringify/samples/option.quoted_match_string.js +++ b/packages/csv-stringify/samples/option.quoted_match_string.js @@ -1,11 +1,12 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - ['a value', '.', 'value.with.dot'], -], { - quoted_match: '.' -}, function(err, records){ - assert.equal(records, 'a value,".","value.with.dot"\n'); -}); +stringify( + [["a value", ".", "value.with.dot"]], + { + quoted_match: ".", + }, + function (err, records) { + assert.equal(records, 'a value,".","value.with.dot"\n'); + }, +); diff --git a/packages/csv-stringify/samples/option.quoted_string.js b/packages/csv-stringify/samples/option.quoted_string.js index 81700fc46..e21b80134 100644 --- a/packages/csv-stringify/samples/option.quoted_string.js +++ b/packages/csv-stringify/samples/option.quoted_string.js @@ -1,11 +1,12 @@ +import { stringify } from "csv-stringify"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify'; -import assert from 'node:assert'; - -stringify([ - ['1', '', true, 2], -], { - quoted_string: true -}, function(err, records){ - assert.equal(records, '"1","",1,2\n'); -}); +stringify( + [["1", "", true, 2]], + { + quoted_string: true, + }, + function (err, records) { + assert.equal(records, '"1","",1,2\n'); + }, +); diff --git a/packages/csv-stringify/samples/option.record_delimiter.js b/packages/csv-stringify/samples/option.record_delimiter.js index 780820803..af6048ae7 100644 --- a/packages/csv-stringify/samples/option.record_delimiter.js +++ b/packages/csv-stringify/samples/option.record_delimiter.js @@ -1,13 +1,15 @@ +import { stringify } from "csv-stringify/sync"; +import assert from "node:assert"; -import { stringify } from 'csv-stringify/sync'; -import assert from 'node:assert'; +const records = stringify( + [ + ["a", "b"], + ["c", "d"], + ], + { + record_delimiter: "|", + eof: false, + }, +); -const records = stringify([ - ['a', 'b'], - ['c', 'd'] -], { - record_delimiter: '|', - eof: false, -}); - -assert.equal(records, 'a,b|c,d'); +assert.equal(records, "a,b|c,d"); diff --git a/packages/csv/.eslintrc.yml b/packages/csv/.eslintrc.yml deleted file mode 100644 index 4581986eb..000000000 --- a/packages/csv/.eslintrc.yml +++ /dev/null @@ -1,21 +0,0 @@ -env: - commonjs: true - es6: true - node: true -extends: "eslint:recommended" -globals: - Atomics: "readonly" - SharedArrayBuffer: "readonly" -parserOptions: - ecmaVersion: "latest" - sourceType: "module" -rules: - no-var: "error" - semi: "error" - indent: ["error", 2] - linebreak-style: ["error", "unix"] - no-multi-spaces: "error" - space-in-parens: "error" - no-multiple-empty-lines: "error" - prefer-const: "error" - no-use-before-define: "error" diff --git a/packages/csv/.travis.yml b/packages/csv/.travis.yml deleted file mode 100644 index 68e5391ac..000000000 --- a/packages/csv/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - "10" - - "11" - - "12" diff --git a/packages/csv/coffeelint.json b/packages/csv/coffeelint.json deleted file mode 100644 index db57f258d..000000000 --- a/packages/csv/coffeelint.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "arrow_spacing": { - "level": "ignore" - }, - "braces_spacing": { - "level": "ignore", - "spaces": 0, - "empty_object_spaces": 0 - }, - "camel_case_classes": { - "level": "error" - }, - "coffeescript_error": { - "level": "error" - }, - "colon_assignment_spacing": { - "level": "ignore", - "spacing": { - "left": 0, - "right": 0 - } - }, - "cyclomatic_complexity": { - "level": "ignore", - "value": 10 - }, - "duplicate_key": { - "level": "error" - }, - "empty_constructor_needs_parens": { - "level": "ignore" - }, - "ensure_comprehensions": { - "level": "warn" - }, - "eol_last": { - "level": "ignore" - }, - "indentation": { - "value": 2, - "level": "error" - }, - "line_endings": { - "level": "error", - "value": "unix" - }, - "max_line_length": { - "value": 80, - "level": "ignore", - "limitComments": true - }, - "missing_fat_arrows": { - "level": "ignore", - "is_strict": false - }, - "newlines_after_classes": { - "value": 3, - "level": "ignore" - }, - "no_backticks": { - "level": "error" - }, - "no_debugger": { - "level": "warn", - "console": false - }, - "no_empty_functions": { - "level": "ignore" - }, - "no_empty_param_list": { - "level": "ignore" - }, - "no_implicit_braces": { - "level": "ignore", - "strict": true - }, - "no_implicit_parens": { - "level": "ignore", - "strict": true - }, - "no_interpolation_in_single_quotes": { - "level": "ignore" - }, - "no_nested_string_interpolation": { - "level": "warn" - }, - "no_plusplus": { - "level": "ignore" - }, - "no_private_function_fat_arrows": { - "level": "warn" - }, - "no_stand_alone_at": { - "level": "ignore" - }, - "no_tabs": { - "level": "error" - }, - "no_this": { - "level": "ignore" - }, - "no_throwing_strings": { - "level": "error" - }, - "no_trailing_semicolons": { - "level": "error" - }, - "no_trailing_whitespace": { - "level": "error", - "allowed_in_comments": false, - "allowed_in_empty_lines": true - }, - "no_unnecessary_double_quotes": { - "level": "ignore" - }, - "no_unnecessary_fat_arrows": { - "level": "warn" - }, - "non_empty_constructor_needs_parens": { - "level": "ignore" - }, - "prefer_english_operator": { - "level": "ignore", - "doubleNotLevel": "ignore" - }, - "space_operators": { - "level": "ignore" - }, - "spacing_after_comma": { - "level": "ignore" - }, - "transform_messes_up_line_numbers": { - "level": "warn" - } -} diff --git a/packages/csv/dist/cjs/index.cjs b/packages/csv/dist/cjs/index.cjs index abf4f5c04..c28807123 100644 --- a/packages/csv/dist/cjs/index.cjs +++ b/packages/csv/dist/cjs/index.cjs @@ -7,54 +7,54 @@ const init_state$1 = (options) => { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. -const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { +const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -63,13 +63,13 @@ const normalize_options$2 = (opts) => { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -77,28 +77,32 @@ const normalize_options$2 = (opts) => { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -113,7 +117,7 @@ const read = (options, state, size, push, close) => { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -143,48 +147,54 @@ const read = (options, state, size, push, close) => { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -193,7 +203,15 @@ const read = (options, state, size, push, close) => { } }; -const Generator = function(options = {}){ +/* +CSV Generate - main module + +Please look at the [project documentation](https://csv.js.org/generate/) for +additional information. +*/ + + +const Generator = function (options = {}) { this.options = normalize_options$2(options); // Call parent constructor stream.Readable.call(this, this.options); @@ -203,70 +221,77 @@ const Generator = function(options = {}){ util.inherits(Generator, stream.Readable); // Stop the generation. -Generator.prototype.end = function(){ +Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. -Generator.prototype._read = function(size){ +Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; -Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); +Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. -Generator.prototype.__push = function(record){ +Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; -const generate = function(){ +const generate = function () { let options; let callback; - if(arguments.length === 2){ + if (arguments.length === 2) { options = arguments[0]; callback = arguments[1]; - }else if(arguments.length === 1){ - if(typeof arguments[0] === 'function'){ + } else if (arguments.length === 1) { + if (typeof arguments[0] === "function") { options = {}; callback = arguments[0]; - }else { + } else { options = arguments[0]; } - }else if(arguments.length === 0){ + } else if (arguments.length === 0) { options = {}; } const generator = new Generator(options); - if(callback){ + if (callback) { const data = []; - generator.on('readable', function(){ - let d; while((d = generator.read()) !== null){ + generator.on("readable", function () { + let d; + while ((d = generator.read()) !== null) { data.push(d); } }); - generator.on('error', callback); - generator.on('end', function(){ - if(generator.options.objectMode){ + generator.on("error", callback); + generator.on("end", function () { + if (generator.options.objectMode) { callback(null, data); - }else { - if(generator.options.encoding){ - callback(null, data.join('')); - }else { + } else { + if (generator.options.encoding) { + callback(null, data.join("")); + } else { callback(null, Buffer.concat(data)); } } @@ -275,68 +300,72 @@ const generate = function(){ return generator; }; -const is_object$1 = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); +const is_object$1 = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; let CsvError$1 = class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = Buffer.isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = Buffer.isBuffer(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } }; -const normalize_columns_array = function(columns){ +const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object$1(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError$1('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object$1(column)) { + if (typeof column.name !== "string") { + throw new CsvError$1("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError$1('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError$1("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; -class ResizeableBuffer{ - constructor(size=100){ +class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(Buffer.isBuffer(val)){ + prepend(val) { + if (Buffer.isBuffer(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -344,44 +373,44 @@ class ResizeableBuffer{ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -396,7 +425,7 @@ const nl$1 = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal const space = 32; const tab = 9; -const init_state = function(options){ +const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -406,9 +435,14 @@ const init_state = function(options){ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: Buffer.isBuffer(options.escape) && Buffer.isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + Buffer.isBuffer(options.escape) && + Buffer.isBuffer(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -426,454 +460,700 @@ const init_state = function(options){ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; -const underscore$1 = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore$1 = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options$1 = function(opts){ +const normalize_options$1 = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore$1(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError$1('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError$1( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError$1('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError$1( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!Buffer.isBuffer(options.comment)){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!Buffer.isBuffer(options.comment)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!Buffer.isBuffer(delimiter) || delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!Buffer.isBuffer(delimiter) || delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!Buffer.isBuffer(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!Buffer.isBuffer(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError$1('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); - } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError$1('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError$1( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); + } + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError$1( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(Buffer.isBuffer(options.objname)){ - if(options.objname.length === 0){ + } else if (Buffer.isBuffer(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!Buffer.isBuffer(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!Buffer.isBuffer(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || Buffer.isBuffer(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + Buffer.isBuffer(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! Buffer.isBuffer(rd)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !Buffer.isBuffer(rd)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); - } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); + } + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); - } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); + } + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; -const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); +const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -884,21 +1164,21 @@ const boms = { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; -const transform$1 = function(original_options = {}) { +const transform$1 = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options$1(original_options); return { @@ -906,10 +1186,11 @@ const transform$1 = function(original_options = {}) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -919,55 +1200,73 @@ const transform$1 = function(original_options = {}) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options$1({...this.original_options, encoding: encoding}); + this.options = normalize_options$1({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -976,51 +1275,62 @@ const transform$1 = function(original_options = {}) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -1028,74 +1338,122 @@ const transform$1 = function(original_options = {}) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError$1('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError$1('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError$1( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -1103,18 +1461,24 @@ const transform$1 = function(original_options = {}) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -1124,157 +1488,218 @@ const transform$1 = function(original_options = {}) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError$1('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError$1('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError$1('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError$1('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError$1('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError$1( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError$1( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -1285,45 +1710,53 @@ const transform$1 = function(original_options = {}) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -1331,19 +1764,28 @@ const transform$1 = function(original_options = {}) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError$1('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError$1( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -1351,92 +1793,98 @@ const transform$1 = function(original_options = {}) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -1450,46 +1898,53 @@ const transform$1 = function(original_options = {}) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -1497,13 +1952,13 @@ const transform$1 = function(original_options = {}) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -1511,32 +1966,32 @@ const transform$1 = function(original_options = {}) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -1546,168 +2001,205 @@ const transform$1 = function(original_options = {}) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; +/* +CSV Parse + +Please look at the [project documentation](https://csv.js.org/parse/) for +additional information. +*/ + + class Parser extends stream.Transform { - constructor(opts = {}){ - super({...{readableObjectMode: true}, ...opts, encoding: null}); - this.api = transform$1({on_skip: (err, chunk) => { - this.emit('skip', err, chunk); - }, ...opts}); + constructor(opts = {}) { + super({ ...{ readableObjectMode: true }, ...opts, encoding: null }); + this.api = transform$1({ + on_skip: (err, chunk) => { + this.emit("skip", err, chunk); + }, + ...opts, + }); // Backward compatibility this.state = this.api.state; this.options = this.api.options; this.info = this.api.info; } // Implementation of `Transform._transform` - _transform(buf, _, callback){ - if(this.state.stop === true){ + _transform(buf, _, callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(buf, false, (record) => { - this.push(record); - }, () => { - this.push(null); - this.end(); - // Fix #333 and break #410 - // ko: api.stream.iterator.coffee - // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) - // ko: api.stream.finished # aborted (with Readable) - // this.destroy() - // Fix #410 and partially break #333 - // ok: api.stream.iterator.coffee - // ok: api.stream.finished # aborted (with generate()) - // broken: api.stream.finished # aborted (with Readable) - this.on('end', this.destroy); - }); - if(err !== undefined){ + const err = this.api.parse( + buf, + false, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.end(); + // Fix #333 and break #410 + // ko: api.stream.iterator.coffee + // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) + // ko: api.stream.finished # aborted (with Readable) + // this.destroy() + // Fix #410 and partially break #333 + // ok: api.stream.iterator.coffee + // ok: api.stream.finished # aborted (with generate()) + // broken: api.stream.finished # aborted (with Readable) + this.on("end", this.destroy); + }, + ); + if (err !== undefined) { this.state.stop = true; } callback(err); } // Implementation of `Transform._flush` - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(undefined, true, (record) => { - this.push(record); - }, () => { - this.push(null); - this.on('end', this.destroy); - }); + const err = this.api.parse( + undefined, + true, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.on("end", this.destroy); + }, + ); callback(err); } } -const parse = function(){ +const parse = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (typeof argument === 'string' || Buffer.isBuffer(argument))){ + if ( + data === undefined && + (typeof argument === "string" || Buffer.isBuffer(argument)) + ) { data = argument; - }else if(options === undefined && is_object$1(argument)){ + } else if (options === undefined && is_object$1(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError$1('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` - ], options || {}); + } else { + throw new CsvError$1( + "CSV_INVALID_ARGUMENT", + ["Invalid argument:", `got ${JSON.stringify(argument)} at index ${i}`], + options || {}, + ); } } const parser = new Parser(options); - if(callback){ - const records = options === undefined || options.objname === undefined ? [] : {}; - parser.on('readable', function(){ + if (callback) { + const records = + options === undefined || options.objname === undefined ? [] : {}; + parser.on("readable", function () { let record; - while((record = this.read()) !== null){ - if(options === undefined || options.objname === undefined){ + while ((record = this.read()) !== null) { + if (options === undefined || options.objname === undefined) { records.push(record); - }else { + } else { records[record[0]] = record[1]; } } }); - parser.on('error', function(err){ + parser.on("error", function (err) { callback(err, undefined, parser.api.__infoDataSet()); }); - parser.on('end', function(){ + parser.on("end", function () { callback(undefined, records, parser.api.__infoDataSet()); }); } - if(data !== undefined){ - const writer = function(){ + if (data !== undefined) { + const writer = function () { parser.write(data); parser.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } return parser; }; -const Transformer = function(options = {}, handler){ +/* +Stream Transform + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -1723,20 +2215,21 @@ const Transformer = function(options = {}, handler){ util.inherits(Transformer, stream.Transform); -Transformer.prototype._transform = function(chunk, _, cb){ +Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -1748,108 +2241,111 @@ Transformer.prototype._transform = function(chunk, _, cb){ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; -Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ +Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; -Transformer.prototype.__done = function(err, chunks, cb){ +Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; -const transform = function(){ +const transform = function () { let options = {}; let callback, handler, records; - for(let i = 0; i< arguments.length; i++){ + for (let i = 0; i < arguments.length; i++) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { if (handler && i === arguments.length - 1) { callback = argument; } else { handler = argument; } - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } const transformer = new Transformer(options, handler); let error = false; if (records) { - const writer = function(){ - for(const record of records){ - if(error) break; + const writer = function () { + for (const record of records) { + if (error) break; transformer.write(record); } transformer.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } - if(callback || options.consume) { + if (callback || options.consume) { const result = []; - transformer.on('readable', function(){ - let record; while((record = transformer.read()) !== null){ - if(callback){ + transformer.on("readable", function () { + let record; + while ((record = transformer.read()) !== null) { + if (callback) { result.push(record); } } }); - transformer.on('error', function(err){ + transformer.on("error", function (err) { error = true; if (callback) callback(err); }); - transformer.on('end', function(){ + transformer.on("end", function () { if (callback && !error) callback(null, result); }); } @@ -1858,136 +2354,163 @@ const transform = function(){ class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = Buffer.isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = Buffer.isBuffer(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; // Lodash implementation of `get` -const charCodeOfDot = '.'.charCodeAt(0); +const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", +); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; -const getTag = function(value){ +const getTag = function (value) { return Object.prototype.toString.call(value); }; -const isSymbol = function(value){ +const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; -const isKey = function(value, object){ - if(Array.isArray(value)){ +const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; -const stringToPath = function(string){ +const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; -const castPath = function(value, object){ - if(Array.isArray(value)){ +const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; -const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; +const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; -const get = function(object, path){ +const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; -const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ +const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -1995,238 +2518,288 @@ const normalize_columns = function(columns){ return [undefined, columns]; }; -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts) { +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(Buffer.isBuffer(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (Buffer.isBuffer(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (Buffer.isBuffer(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (Buffer.isBuffer(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(Buffer.isBuffer(options.escape)){ + } else if (Buffer.isBuffer(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(Buffer.isBuffer(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (Buffer.isBuffer(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); -const stringifier = function(options, state, info){ +const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -2235,96 +2808,136 @@ const stringifier = function(options, state, info){ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -2334,171 +2947,190 @@ const stringifier = function(options, state, info){ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; +/* +CSV Stringify + +Please look at the [project documentation](https://csv.js.org/stringify/) for +additional information. +*/ + + class Stringifier extends stream.Transform { - constructor(opts = {}){ - super({...{writableObjectMode: true}, ...opts}); + constructor(opts = {}) { + super({ ...{ writableObjectMode: true }, ...opts }); const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; // Expose options this.options = options; // Internal state this.state = { - stop: false + stop: false, }; // Information this.info = { - records: 0 + records: 0, }; this.api = stringifier(this.options, this.state, this.info); this.api.options.on_record = (...args) => { - this.emit('record', ...args); + this.emit("record", ...args); }; } - _transform(chunk, encoding, callback){ - if(this.state.stop === true){ + _transform(chunk, encoding, callback) { + if (this.state.stop === true) { return; } const err = this.api.__transform(chunk, this.push.bind(this)); - if(err !== undefined){ + if (err !== undefined) { this.state.stop = true; } callback(err); } - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { // Note, Node.js 12 call flush even after an error, we must prevent // `callback` from being called in flush without any error. return; } - if(this.info.records === 0){ + if (this.info.records === 0) { this.api.bom(this.push.bind(this)); const err = this.api.headers(this.push.bind(this)); - if(err) callback(err); + if (err) callback(err); } callback(); } } -const stringify = function(){ +const stringify = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (Array.isArray(argument))){ + if (data === undefined && Array.isArray(argument)) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` + } else { + throw new CsvError("CSV_INVALID_ARGUMENT", [ + "Invalid argument:", + `got ${JSON.stringify(argument)} at index ${i}`, ]); } } const stringifier = new Stringifier(options); - if(callback){ + if (callback) { const chunks = []; - stringifier.on('readable', function(){ + stringifier.on("readable", function () { let chunk; - while((chunk = this.read()) !== null){ + while ((chunk = this.read()) !== null) { chunks.push(chunk); } }); - stringifier.on('error', function(err){ + stringifier.on("error", function (err) { callback(err); }); - stringifier.on('end', function(){ + stringifier.on("end", function () { try { - callback(undefined, chunks.join('')); + callback(undefined, chunks.join("")); } catch (err) { // This can happen if the `chunks` is extremely long; it may throw // "Cannot create a string longer than 0x1fffffe8 characters" @@ -2508,17 +3140,17 @@ const stringify = function(){ } }); } - if(data !== undefined){ - const writer = function(){ - for(const record of data){ + if (data !== undefined) { + const writer = function () { + for (const record of data) { stringifier.write(record); } stringifier.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv/dist/cjs/sync.cjs b/packages/csv/dist/cjs/sync.cjs index e48c15b21..660bb5374 100644 --- a/packages/csv/dist/cjs/sync.cjs +++ b/packages/csv/dist/cjs/sync.cjs @@ -7,54 +7,54 @@ const init_state$1 = (options) => { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. -const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { +const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -63,13 +63,13 @@ const normalize_options$2 = (opts) => { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -77,28 +77,32 @@ const normalize_options$2 = (opts) => { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -113,7 +117,7 @@ const read = (options, state, size, push, close) => { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -143,48 +147,54 @@ const read = (options, state, size, push, close) => { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -193,7 +203,15 @@ const read = (options, state, size, push, close) => { } }; -const Generator = function(options = {}){ +/* +CSV Generate - main module + +Please look at the [project documentation](https://csv.js.org/generate/) for +additional information. +*/ + + +const Generator = function (options = {}) { this.options = normalize_options$2(options); // Call parent constructor stream.Readable.call(this, this.options); @@ -203,131 +221,149 @@ const Generator = function(options = {}){ util.inherits(Generator, stream.Readable); // Stop the generation. -Generator.prototype.end = function(){ +Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. -Generator.prototype._read = function(size){ +Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; -Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); +Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. -Generator.prototype.__push = function(record){ +Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; -const generate = function(options){ - if(typeof options === 'string' && /\d+/.test(options)){ +/* +CSV Generate - sync module + +Please look at the [project documentation](https://csv.js.org/generate/) for +additional information. +*/ + + +const generate = function (options) { + if (typeof options === "string" && /\d+/.test(options)) { options = parseInt(options); } - if(Number.isInteger(options)){ - options = {length: options}; - }else if(typeof options !== 'object' || options === null){ - throw Error('Invalid Argument: options must be an object or an integer'); + if (Number.isInteger(options)) { + options = { length: options }; + } else if (typeof options !== "object" || options === null) { + throw Error("Invalid Argument: options must be an object or an integer"); } - if(!Number.isInteger(options.length)){ - throw Error('Invalid Argument: length is not defined'); + if (!Number.isInteger(options.length)) { + throw Error("Invalid Argument: length is not defined"); } const chunks = []; let work = true; const generator = new Generator(options); - generator.push = function(chunk){ - if(chunk === null){ - return work = false; + generator.push = function (chunk) { + if (chunk === null) { + return (work = false); } - chunks.push(chunk); + chunks.push(chunk); }; - while(work){ + while (work) { generator.__read(options.highWaterMark); } - if(!options.objectMode){ - return chunks.join(''); - }else { + if (!options.objectMode) { + return chunks.join(""); + } else { return chunks; } }; let CsvError$1 = class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = Buffer.isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = Buffer.isBuffer(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } }; -const is_object$1 = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); +const is_object$1 = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; -const normalize_columns_array = function(columns){ +const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object$1(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError$1('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object$1(column)) { + if (typeof column.name !== "string") { + throw new CsvError$1("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError$1('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError$1("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; -class ResizeableBuffer{ - constructor(size=100){ +class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(Buffer.isBuffer(val)){ + prepend(val) { + if (Buffer.isBuffer(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -335,44 +371,44 @@ class ResizeableBuffer{ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -387,7 +423,7 @@ const nl$1 = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal const space = 32; const tab = 9; -const init_state = function(options){ +const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -397,9 +433,14 @@ const init_state = function(options){ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: Buffer.isBuffer(options.escape) && Buffer.isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + Buffer.isBuffer(options.escape) && + Buffer.isBuffer(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -417,454 +458,700 @@ const init_state = function(options){ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; -const underscore$1 = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore$1 = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options$1 = function(opts){ +const normalize_options$1 = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore$1(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError$1('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError$1( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError$1('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError$1( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!Buffer.isBuffer(options.comment)){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!Buffer.isBuffer(options.comment)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); } - if(typeof delimiter === 'string'){ + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!Buffer.isBuffer(delimiter) || delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!Buffer.isBuffer(delimiter) || delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!Buffer.isBuffer(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!Buffer.isBuffer(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError$1('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); - } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError$1('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError$1( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); + } + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError$1( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(Buffer.isBuffer(options.objname)){ - if(options.objname.length === 0){ + } else if (Buffer.isBuffer(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); - } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); + } + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!Buffer.isBuffer(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!Buffer.isBuffer(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || Buffer.isBuffer(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + Buffer.isBuffer(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! Buffer.isBuffer(rd)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !Buffer.isBuffer(rd)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); } - if(typeof rd === 'string'){ + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); - } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); + } + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); - } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); + } + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; -const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); +const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -875,21 +1162,21 @@ const boms = { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; -const transform$1 = function(original_options = {}) { +const transform$1 = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options$1(original_options); return { @@ -897,10 +1184,11 @@ const transform$1 = function(original_options = {}) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -910,55 +1198,73 @@ const transform$1 = function(original_options = {}) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options$1({...this.original_options, encoding: encoding}); + this.options = normalize_options$1({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -967,51 +1273,62 @@ const transform$1 = function(original_options = {}) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -1019,74 +1336,122 @@ const transform$1 = function(original_options = {}) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError$1('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError$1('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError$1( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -1094,18 +1459,24 @@ const transform$1 = function(original_options = {}) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -1115,157 +1486,218 @@ const transform$1 = function(original_options = {}) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError$1('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError$1('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError$1('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError$1('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError$1('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError$1( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError$1( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -1276,45 +1708,53 @@ const transform$1 = function(original_options = {}) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -1322,19 +1762,28 @@ const transform$1 = function(original_options = {}) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError$1('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError$1( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -1342,92 +1791,98 @@ const transform$1 = function(original_options = {}) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -1441,46 +1896,53 @@ const transform$1 = function(original_options = {}) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -1488,13 +1950,13 @@ const transform$1 = function(original_options = {}) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -1502,32 +1964,32 @@ const transform$1 = function(original_options = {}) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -1537,189 +1999,214 @@ const transform$1 = function(original_options = {}) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; -const parse = function(data, opts={}){ - if(typeof data === 'string'){ +const parse = function (data, opts = {}) { + if (typeof data === "string") { data = Buffer.from(data); } const records = opts && opts.objname ? {} : []; const parser = transform$1(opts); const push = (record) => { - if(parser.options.objname === undefined) - records.push(record); + if (parser.options.objname === undefined) records.push(record); else { records[record[0]] = record[1]; } }; const close = () => {}; const err1 = parser.parse(data, false, push, close); - if(err1 !== undefined) throw err1; + if (err1 !== undefined) throw err1; const err2 = parser.parse(undefined, true, push, close); - if(err2 !== undefined) throw err2; + if (err2 !== undefined) throw err2; return records; }; // Lodash implementation of `get` -const charCodeOfDot = '.'.charCodeAt(0); +const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", +); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; -const getTag = function(value){ +const getTag = function (value) { return Object.prototype.toString.call(value); }; -const isSymbol = function(value){ +const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; -const isKey = function(value, object){ - if(Array.isArray(value)){ +const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; -const stringToPath = function(string){ +const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; -const castPath = function(value, object){ - if(Array.isArray(value)){ +const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; -const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; +const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; -const get = function(object, path){ +const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; -const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; -const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ +const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -1729,253 +2216,307 @@ const normalize_columns = function(columns){ class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = Buffer.isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = Buffer.isBuffer(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts) { +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(Buffer.isBuffer(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (Buffer.isBuffer(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (Buffer.isBuffer(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (Buffer.isBuffer(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(Buffer.isBuffer(options.escape)){ + } else if (Buffer.isBuffer(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(Buffer.isBuffer(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (Buffer.isBuffer(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); -const stringifier = function(options, state, info){ +const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -1984,96 +2525,136 @@ const stringifier = function(options, state, info){ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -2083,133 +2664,152 @@ const stringifier = function(options, state, info){ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; -const stringify = function(records, opts={}){ +const stringify = function (records, opts = {}) { const data = []; const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; const state = { - stop: false + stop: false, }; // Information const info = { - records: 0 + records: 0, }; const api = stringifier(options, state, info); - for(const record of records){ - const err = api.__transform(record, function(record){ + for (const record of records) { + const err = api.__transform(record, function (record) { data.push(record); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - if(data.length === 0){ + if (data.length === 0) { api.bom((d) => { data.push(d); }); const err = api.headers((headers) => { data.push(headers); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - return data.join(''); + return data.join(""); }; -const Transformer = function(options = {}, handler){ +/* +Stream Transform + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -2225,20 +2825,21 @@ const Transformer = function(options = {}, handler){ util.inherits(Transformer, stream.Transform); -Transformer.prototype._transform = function(chunk, _, cb){ +Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -2250,93 +2851,103 @@ Transformer.prototype._transform = function(chunk, _, cb){ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; -Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ +Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; -Transformer.prototype.__done = function(err, chunks, cb){ +Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; -const transform = function(){ +/* +Stream Transform - sync module + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const transform = function () { // Import arguments normalization let handler, records; let options = {}; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { handler = argument; - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } // Validate arguments let expected_handler_length = 1; - if(options.params){ + if (options.params) { expected_handler_length++; } - if(handler.length > expected_handler_length){ - throw Error('Invalid Handler: only synchonous handlers are supported'); + if (handler.length > expected_handler_length) { + throw Error("Invalid Handler: only synchonous handlers are supported"); } // Start transformation const chunks = []; const transformer = new Transformer(options, handler); - transformer.push = function(chunk){ + transformer.push = function (chunk) { chunks.push(chunk); }; - for(const record of records){ - transformer._transform(record, null, function(){}); + for (const record of records) { + transformer._transform(record, null, function () {}); } - return chunks; + return chunks; }; exports.generate = generate; diff --git a/packages/csv/dist/esm/index.js b/packages/csv/dist/esm/index.js index 0f039709e..252d7ff32 100644 --- a/packages/csv/dist/esm/index.js +++ b/packages/csv/dist/esm/index.js @@ -2000,7 +2000,7 @@ EventEmitter.init = function() { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5198,54 +5198,54 @@ const init_state$1 = (options) => { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. -const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { +const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5254,13 +5254,13 @@ const normalize_options$2 = (opts) => { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5268,28 +5268,32 @@ const normalize_options$2 = (opts) => { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5304,7 +5308,7 @@ const read = (options, state, size, push, close) => { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5334,48 +5338,54 @@ const read = (options, state, size, push, close) => { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5384,7 +5394,7 @@ const read = (options, state, size, push, close) => { } }; -const Generator = function(options = {}){ +const Generator = function (options = {}) { this.options = normalize_options$2(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5394,70 +5404,77 @@ const Generator = function(options = {}){ util.inherits(Generator, Stream.Readable); // Stop the generation. -Generator.prototype.end = function(){ +Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. -Generator.prototype._read = function(size){ +Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; -Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); +Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. -Generator.prototype.__push = function(record){ +Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; -const generate = function(){ +const generate = function () { let options; let callback; - if(arguments.length === 2){ + if (arguments.length === 2) { options = arguments[0]; callback = arguments[1]; - }else if(arguments.length === 1){ - if(typeof arguments[0] === 'function'){ + } else if (arguments.length === 1) { + if (typeof arguments[0] === "function") { options = {}; callback = arguments[0]; - }else { + } else { options = arguments[0]; } - }else if(arguments.length === 0){ + } else if (arguments.length === 0) { options = {}; } const generator = new Generator(options); - if(callback){ + if (callback) { const data = []; - generator.on('readable', function(){ - let d; while((d = generator.read()) !== null){ + generator.on("readable", function () { + let d; + while ((d = generator.read()) !== null) { data.push(d); } }); - generator.on('error', callback); - generator.on('end', function(){ - if(generator.options.objectMode){ + generator.on("error", callback); + generator.on("end", function () { + if (generator.options.objectMode) { callback(null, data); - }else { - if(generator.options.encoding){ - callback(null, data.join('')); - }else { + } else { + if (generator.options.encoding) { + callback(null, data.join("")); + } else { callback(null, Buffer.concat(data)); } } @@ -5466,68 +5483,72 @@ const generate = function(){ return generator; }; -const is_object$1 = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); +const is_object$1 = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; let CsvError$1 = class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } }; -const normalize_columns_array = function(columns){ +const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object$1(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError$1('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object$1(column)) { + if (typeof column.name !== "string") { + throw new CsvError$1("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError$1('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError$1("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; -class ResizeableBuffer{ - constructor(size=100){ +class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer$1(val)){ + prepend(val) { + if (isBuffer$1(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -5535,44 +5556,44 @@ class ResizeableBuffer{ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -5587,7 +5608,7 @@ const nl$1 = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal const space = 32; const tab = 9; -const init_state = function(options){ +const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -5597,9 +5618,14 @@ const init_state = function(options){ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer$1(options.escape) && isBuffer$1(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer$1(options.escape) && + isBuffer$1(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -5617,454 +5643,700 @@ const init_state = function(options){ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; -const underscore$1 = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore$1 = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options$1 = function(opts){ +const normalize_options$1 = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore$1(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError$1('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError$1( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError$1('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError$1( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer$1(options.comment)){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer$1(options.comment)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer$1(delimiter) || delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer$1(delimiter) || delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer$1(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer$1(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError$1('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError$1( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError$1('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError$1( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer$1(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer$1(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer$1(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer$1(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer$1(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer$1(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer$1(rd)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer$1(rd)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; -const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); +const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -6075,21 +6347,21 @@ const boms = { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; -const transform$1 = function(original_options = {}) { +const transform$1 = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options$1(original_options); return { @@ -6097,10 +6369,11 @@ const transform$1 = function(original_options = {}) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -6110,55 +6383,73 @@ const transform$1 = function(original_options = {}) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options$1({...this.original_options, encoding: encoding}); + this.options = normalize_options$1({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -6167,51 +6458,62 @@ const transform$1 = function(original_options = {}) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -6219,74 +6521,122 @@ const transform$1 = function(original_options = {}) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError$1('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError$1('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError$1( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -6294,18 +6644,24 @@ const transform$1 = function(original_options = {}) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -6315,157 +6671,218 @@ const transform$1 = function(original_options = {}) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError$1('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError$1('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError$1('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError$1('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError$1('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError$1( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError$1( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -6476,45 +6893,53 @@ const transform$1 = function(original_options = {}) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -6522,19 +6947,28 @@ const transform$1 = function(original_options = {}) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError$1('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError$1( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -6542,92 +6976,98 @@ const transform$1 = function(original_options = {}) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -6641,46 +7081,53 @@ const transform$1 = function(original_options = {}) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -6688,13 +7135,13 @@ const transform$1 = function(original_options = {}) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -6702,32 +7149,32 @@ const transform$1 = function(original_options = {}) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -6737,168 +7184,197 @@ const transform$1 = function(original_options = {}) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; class Parser extends Transform { - constructor(opts = {}){ - super({...{readableObjectMode: true}, ...opts, encoding: null}); - this.api = transform$1({on_skip: (err, chunk) => { - this.emit('skip', err, chunk); - }, ...opts}); + constructor(opts = {}) { + super({ ...{ readableObjectMode: true }, ...opts, encoding: null }); + this.api = transform$1({ + on_skip: (err, chunk) => { + this.emit("skip", err, chunk); + }, + ...opts, + }); // Backward compatibility this.state = this.api.state; this.options = this.api.options; this.info = this.api.info; } // Implementation of `Transform._transform` - _transform(buf, _, callback){ - if(this.state.stop === true){ + _transform(buf, _, callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(buf, false, (record) => { - this.push(record); - }, () => { - this.push(null); - this.end(); - // Fix #333 and break #410 - // ko: api.stream.iterator.coffee - // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) - // ko: api.stream.finished # aborted (with Readable) - // this.destroy() - // Fix #410 and partially break #333 - // ok: api.stream.iterator.coffee - // ok: api.stream.finished # aborted (with generate()) - // broken: api.stream.finished # aborted (with Readable) - this.on('end', this.destroy); - }); - if(err !== undefined){ + const err = this.api.parse( + buf, + false, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.end(); + // Fix #333 and break #410 + // ko: api.stream.iterator.coffee + // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) + // ko: api.stream.finished # aborted (with Readable) + // this.destroy() + // Fix #410 and partially break #333 + // ok: api.stream.iterator.coffee + // ok: api.stream.finished # aborted (with generate()) + // broken: api.stream.finished # aborted (with Readable) + this.on("end", this.destroy); + }, + ); + if (err !== undefined) { this.state.stop = true; } callback(err); } // Implementation of `Transform._flush` - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(undefined, true, (record) => { - this.push(record); - }, () => { - this.push(null); - this.on('end', this.destroy); - }); + const err = this.api.parse( + undefined, + true, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.on("end", this.destroy); + }, + ); callback(err); } } -const parse = function(){ +const parse = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (typeof argument === 'string' || isBuffer$1(argument))){ + if ( + data === undefined && + (typeof argument === "string" || isBuffer$1(argument)) + ) { data = argument; - }else if(options === undefined && is_object$1(argument)){ + } else if (options === undefined && is_object$1(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError$1('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` - ], options || {}); + } else { + throw new CsvError$1( + "CSV_INVALID_ARGUMENT", + ["Invalid argument:", `got ${JSON.stringify(argument)} at index ${i}`], + options || {}, + ); } } const parser = new Parser(options); - if(callback){ - const records = options === undefined || options.objname === undefined ? [] : {}; - parser.on('readable', function(){ + if (callback) { + const records = + options === undefined || options.objname === undefined ? [] : {}; + parser.on("readable", function () { let record; - while((record = this.read()) !== null){ - if(options === undefined || options.objname === undefined){ + while ((record = this.read()) !== null) { + if (options === undefined || options.objname === undefined) { records.push(record); - }else { + } else { records[record[0]] = record[1]; } } }); - parser.on('error', function(err){ + parser.on("error", function (err) { callback(err, undefined, parser.api.__infoDataSet()); }); - parser.on('end', function(){ + parser.on("end", function () { callback(undefined, records, parser.api.__infoDataSet()); }); } - if(data !== undefined){ - const writer = function(){ + if (data !== undefined) { + const writer = function () { parser.write(data); parser.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } return parser; }; -const Transformer = function(options = {}, handler){ +/* +Stream Transform + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -6914,20 +7390,21 @@ const Transformer = function(options = {}, handler){ util.inherits(Transformer, Stream.Transform); -Transformer.prototype._transform = function(chunk, _, cb){ +Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -6939,108 +7416,111 @@ Transformer.prototype._transform = function(chunk, _, cb){ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; -Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ +Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; -Transformer.prototype.__done = function(err, chunks, cb){ +Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; -const transform = function(){ +const transform = function () { let options = {}; let callback, handler, records; - for(let i = 0; i< arguments.length; i++){ + for (let i = 0; i < arguments.length; i++) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { if (handler && i === arguments.length - 1) { callback = argument; } else { handler = argument; } - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } const transformer = new Transformer(options, handler); let error = false; if (records) { - const writer = function(){ - for(const record of records){ - if(error) break; + const writer = function () { + for (const record of records) { + if (error) break; transformer.write(record); } transformer.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } - if(callback || options.consume) { + if (callback || options.consume) { const result = []; - transformer.on('readable', function(){ - let record; while((record = transformer.read()) !== null){ - if(callback){ + transformer.on("readable", function () { + let record; + while ((record = transformer.read()) !== null) { + if (callback) { result.push(record); } } }); - transformer.on('error', function(err){ + transformer.on("error", function (err) { error = true; if (callback) callback(err); }); - transformer.on('end', function(){ + transformer.on("end", function () { if (callback && !error) callback(null, result); }); } @@ -7049,136 +7529,163 @@ const transform = function(){ class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; // Lodash implementation of `get` -const charCodeOfDot = '.'.charCodeAt(0); +const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", +); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; -const getTag = function(value){ +const getTag = function (value) { return Object.prototype.toString.call(value); }; -const isSymbol = function(value){ +const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; -const isKey = function(value, object){ - if(Array.isArray(value)){ +const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; -const stringToPath = function(string){ +const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; -const castPath = function(value, object){ - if(Array.isArray(value)){ +const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; -const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; +const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; -const get = function(object, path){ +const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; -const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ +const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -7186,238 +7693,288 @@ const normalize_columns = function(columns){ return [undefined, columns]; }; -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts) { +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer$1(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer$1(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer$1(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer$1(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer$1(options.escape)){ + } else if (isBuffer$1(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer$1(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer$1(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); -const stringifier = function(options, state, info){ +const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -7426,96 +7983,136 @@ const stringifier = function(options, state, info){ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -7525,171 +8122,190 @@ const stringifier = function(options, state, info){ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; +/* +CSV Stringify + +Please look at the [project documentation](https://csv.js.org/stringify/) for +additional information. +*/ + + class Stringifier extends Transform { - constructor(opts = {}){ - super({...{writableObjectMode: true}, ...opts}); + constructor(opts = {}) { + super({ ...{ writableObjectMode: true }, ...opts }); const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; // Expose options this.options = options; // Internal state this.state = { - stop: false + stop: false, }; // Information this.info = { - records: 0 + records: 0, }; this.api = stringifier(this.options, this.state, this.info); this.api.options.on_record = (...args) => { - this.emit('record', ...args); + this.emit("record", ...args); }; } - _transform(chunk, encoding, callback){ - if(this.state.stop === true){ + _transform(chunk, encoding, callback) { + if (this.state.stop === true) { return; } const err = this.api.__transform(chunk, this.push.bind(this)); - if(err !== undefined){ + if (err !== undefined) { this.state.stop = true; } callback(err); } - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { // Note, Node.js 12 call flush even after an error, we must prevent // `callback` from being called in flush without any error. return; } - if(this.info.records === 0){ + if (this.info.records === 0) { this.api.bom(this.push.bind(this)); const err = this.api.headers(this.push.bind(this)); - if(err) callback(err); + if (err) callback(err); } callback(); } } -const stringify = function(){ +const stringify = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (Array.isArray(argument))){ + if (data === undefined && Array.isArray(argument)) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` + } else { + throw new CsvError("CSV_INVALID_ARGUMENT", [ + "Invalid argument:", + `got ${JSON.stringify(argument)} at index ${i}`, ]); } } const stringifier = new Stringifier(options); - if(callback){ + if (callback) { const chunks = []; - stringifier.on('readable', function(){ + stringifier.on("readable", function () { let chunk; - while((chunk = this.read()) !== null){ + while ((chunk = this.read()) !== null) { chunks.push(chunk); } }); - stringifier.on('error', function(err){ + stringifier.on("error", function (err) { callback(err); }); - stringifier.on('end', function(){ + stringifier.on("end", function () { try { - callback(undefined, chunks.join('')); + callback(undefined, chunks.join("")); } catch (err) { // This can happen if the `chunks` is extremely long; it may throw // "Cannot create a string longer than 0x1fffffe8 characters" @@ -7699,17 +8315,17 @@ const stringify = function(){ } }); } - if(data !== undefined){ - const writer = function(){ - for(const record of data){ + if (data !== undefined) { + const writer = function () { + for (const record of data) { stringifier.write(record); } stringifier.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv/dist/esm/sync.js b/packages/csv/dist/esm/sync.js index 92035173f..4e2dbcda0 100644 --- a/packages/csv/dist/esm/sync.js +++ b/packages/csv/dist/esm/sync.js @@ -2000,7 +2000,7 @@ EventEmitter.init = function() { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5198,54 +5198,54 @@ const init_state$1 = (options) => { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. -const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { +const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5254,13 +5254,13 @@ const normalize_options$2 = (opts) => { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5268,28 +5268,32 @@ const normalize_options$2 = (opts) => { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5304,7 +5308,7 @@ const read = (options, state, size, push, close) => { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5334,48 +5338,54 @@ const read = (options, state, size, push, close) => { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5384,7 +5394,7 @@ const read = (options, state, size, push, close) => { } }; -const Generator = function(options = {}){ +const Generator = function (options = {}) { this.options = normalize_options$2(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5394,131 +5404,149 @@ const Generator = function(options = {}){ util.inherits(Generator, Stream.Readable); // Stop the generation. -Generator.prototype.end = function(){ +Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. -Generator.prototype._read = function(size){ +Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; -Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); +Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. -Generator.prototype.__push = function(record){ +Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; -const generate = function(options){ - if(typeof options === 'string' && /\d+/.test(options)){ +/* +CSV Generate - sync module + +Please look at the [project documentation](https://csv.js.org/generate/) for +additional information. +*/ + + +const generate = function (options) { + if (typeof options === "string" && /\d+/.test(options)) { options = parseInt(options); } - if(Number.isInteger(options)){ - options = {length: options}; - }else if(typeof options !== 'object' || options === null){ - throw Error('Invalid Argument: options must be an object or an integer'); + if (Number.isInteger(options)) { + options = { length: options }; + } else if (typeof options !== "object" || options === null) { + throw Error("Invalid Argument: options must be an object or an integer"); } - if(!Number.isInteger(options.length)){ - throw Error('Invalid Argument: length is not defined'); + if (!Number.isInteger(options.length)) { + throw Error("Invalid Argument: length is not defined"); } const chunks = []; let work = true; const generator = new Generator(options); - generator.push = function(chunk){ - if(chunk === null){ - return work = false; + generator.push = function (chunk) { + if (chunk === null) { + return (work = false); } - chunks.push(chunk); + chunks.push(chunk); }; - while(work){ + while (work) { generator.__read(options.highWaterMark); } - if(!options.objectMode){ - return chunks.join(''); - }else { + if (!options.objectMode) { + return chunks.join(""); + } else { return chunks; } }; let CsvError$1 = class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } }; -const is_object$1 = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); +const is_object$1 = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; -const normalize_columns_array = function(columns){ +const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object$1(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError$1('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object$1(column)) { + if (typeof column.name !== "string") { + throw new CsvError$1("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError$1('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError$1("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; -class ResizeableBuffer{ - constructor(size=100){ +class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer$1(val)){ + prepend(val) { + if (isBuffer$1(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -5526,44 +5554,44 @@ class ResizeableBuffer{ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -5578,7 +5606,7 @@ const nl$1 = 10; // `\n`, newline, 0x0A in hexadecimal, 10 in decimal const space = 32; const tab = 9; -const init_state = function(options){ +const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -5588,9 +5616,14 @@ const init_state = function(options){ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer$1(options.escape) && isBuffer$1(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer$1(options.escape) && + isBuffer$1(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -5608,454 +5641,700 @@ const init_state = function(options){ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; -const underscore$1 = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore$1 = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options$1 = function(opts){ +const normalize_options$1 = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore$1(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError$1('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError$1( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError$1('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError$1( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer$1(options.comment)){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer$1(options.comment)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer$1(delimiter) || delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer$1(delimiter) || delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer$1(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer$1(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError$1('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError$1( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError$1('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError$1( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer$1(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer$1(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer$1(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer$1(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer$1(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer$1(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer$1(rd)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer$1(rd)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; -const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); +const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -6066,21 +6345,21 @@ const boms = { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; -const transform$1 = function(original_options = {}) { +const transform$1 = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options$1(original_options); return { @@ -6088,10 +6367,11 @@ const transform$1 = function(original_options = {}) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -6101,55 +6381,73 @@ const transform$1 = function(original_options = {}) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options$1({...this.original_options, encoding: encoding}); + this.options = normalize_options$1({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -6158,51 +6456,62 @@ const transform$1 = function(original_options = {}) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -6210,74 +6519,122 @@ const transform$1 = function(original_options = {}) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError$1('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError$1('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError$1( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -6285,18 +6642,24 @@ const transform$1 = function(original_options = {}) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -6306,157 +6669,218 @@ const transform$1 = function(original_options = {}) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError$1('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError$1('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError$1('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError$1('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError$1('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError$1( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError$1( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -6467,45 +6891,53 @@ const transform$1 = function(original_options = {}) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -6513,19 +6945,28 @@ const transform$1 = function(original_options = {}) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError$1('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError$1( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -6533,92 +6974,98 @@ const transform$1 = function(original_options = {}) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -6632,46 +7079,53 @@ const transform$1 = function(original_options = {}) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -6679,13 +7133,13 @@ const transform$1 = function(original_options = {}) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -6693,32 +7147,32 @@ const transform$1 = function(original_options = {}) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -6728,189 +7182,214 @@ const transform$1 = function(original_options = {}) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; -const parse = function(data, opts={}){ - if(typeof data === 'string'){ +const parse = function (data, opts = {}) { + if (typeof data === "string") { data = Buffer.from(data); } const records = opts && opts.objname ? {} : []; const parser = transform$1(opts); const push = (record) => { - if(parser.options.objname === undefined) - records.push(record); + if (parser.options.objname === undefined) records.push(record); else { records[record[0]] = record[1]; } }; const close = () => {}; const err1 = parser.parse(data, false, push, close); - if(err1 !== undefined) throw err1; + if (err1 !== undefined) throw err1; const err2 = parser.parse(undefined, true, push, close); - if(err2 !== undefined) throw err2; + if (err2 !== undefined) throw err2; return records; }; // Lodash implementation of `get` -const charCodeOfDot = '.'.charCodeAt(0); +const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", +); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; -const getTag = function(value){ +const getTag = function (value) { return Object.prototype.toString.call(value); }; -const isSymbol = function(value){ +const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; -const isKey = function(value, object){ - if(Array.isArray(value)){ +const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; -const stringToPath = function(string){ +const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; -const castPath = function(value, object){ - if(Array.isArray(value)){ +const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; -const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; +const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; -const get = function(object, path){ +const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; -const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); +const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; -const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ +const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -6920,253 +7399,307 @@ const normalize_columns = function(columns){ class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } -const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); +const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; -const normalize_options = function(opts) { +const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer$1(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer$1(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer$1(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer$1(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer$1(options.escape)){ + } else if (isBuffer$1(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer$1(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer$1(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); -const stringifier = function(options, state, info){ +const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -7175,96 +7708,136 @@ const stringifier = function(options, state, info){ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -7274,133 +7847,152 @@ const stringifier = function(options, state, info){ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; -const stringify = function(records, opts={}){ +const stringify = function (records, opts = {}) { const data = []; const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; const state = { - stop: false + stop: false, }; // Information const info = { - records: 0 + records: 0, }; const api = stringifier(options, state, info); - for(const record of records){ - const err = api.__transform(record, function(record){ + for (const record of records) { + const err = api.__transform(record, function (record) { data.push(record); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - if(data.length === 0){ + if (data.length === 0) { api.bom((d) => { data.push(d); }); const err = api.headers((headers) => { data.push(headers); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - return data.join(''); + return data.join(""); }; -const Transformer = function(options = {}, handler){ +/* +Stream Transform + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -7416,20 +8008,21 @@ const Transformer = function(options = {}, handler){ util.inherits(Transformer, Stream.Transform); -Transformer.prototype._transform = function(chunk, _, cb){ +Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -7441,93 +8034,103 @@ Transformer.prototype._transform = function(chunk, _, cb){ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; -Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ +Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; -Transformer.prototype.__done = function(err, chunks, cb){ +Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; -const transform = function(){ +/* +Stream Transform - sync module + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const transform = function () { // Import arguments normalization let handler, records; let options = {}; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { handler = argument; - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } // Validate arguments let expected_handler_length = 1; - if(options.params){ + if (options.params) { expected_handler_length++; } - if(handler.length > expected_handler_length){ - throw Error('Invalid Handler: only synchonous handlers are supported'); + if (handler.length > expected_handler_length) { + throw Error("Invalid Handler: only synchonous handlers are supported"); } // Start transformation const chunks = []; const transformer = new Transformer(options, handler); - transformer.push = function(chunk){ + transformer.push = function (chunk) { chunks.push(chunk); }; - for(const record of records){ - transformer._transform(record, null, function(){}); + for (const record of records) { + transformer._transform(record, null, function () {}); } - return chunks; + return chunks; }; export { generate, parse, stringify, transform }; diff --git a/packages/csv/dist/iife/index.js b/packages/csv/dist/iife/index.js index 14fc6aaeb..eb9bec7da 100644 --- a/packages/csv/dist/iife/index.js +++ b/packages/csv/dist/iife/index.js @@ -2003,7 +2003,7 @@ var csv = (function (exports) { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5201,54 +5201,54 @@ var csv = (function (exports) { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. - const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { + const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5257,13 +5257,13 @@ var csv = (function (exports) { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5271,28 +5271,32 @@ var csv = (function (exports) { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5307,7 +5311,7 @@ var csv = (function (exports) { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5337,48 +5341,54 @@ var csv = (function (exports) { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5387,7 +5397,7 @@ var csv = (function (exports) { } }; - const Generator = function(options = {}){ + const Generator = function (options = {}) { this.options = normalize_options$2(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5397,70 +5407,77 @@ var csv = (function (exports) { util.inherits(Generator, Stream.Readable); // Stop the generation. - Generator.prototype.end = function(){ + Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. - Generator.prototype._read = function(size){ + Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; - Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); + Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. - Generator.prototype.__push = function(record){ + Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; - const generate = function(){ + const generate = function () { let options; let callback; - if(arguments.length === 2){ + if (arguments.length === 2) { options = arguments[0]; callback = arguments[1]; - }else if(arguments.length === 1){ - if(typeof arguments[0] === 'function'){ + } else if (arguments.length === 1) { + if (typeof arguments[0] === "function") { options = {}; callback = arguments[0]; - }else { + } else { options = arguments[0]; } - }else if(arguments.length === 0){ + } else if (arguments.length === 0) { options = {}; } const generator = new Generator(options); - if(callback){ + if (callback) { const data = []; - generator.on('readable', function(){ - let d; while((d = generator.read()) !== null){ + generator.on("readable", function () { + let d; + while ((d = generator.read()) !== null) { data.push(d); } }); - generator.on('error', callback); - generator.on('end', function(){ - if(generator.options.objectMode){ + generator.on("error", callback); + generator.on("end", function () { + if (generator.options.objectMode) { callback(null, data); - }else { - if(generator.options.encoding){ - callback(null, data.join('')); - }else { + } else { + if (generator.options.encoding) { + callback(null, data.join("")); + } else { callback(null, Buffer.concat(data)); } } @@ -5469,68 +5486,72 @@ var csv = (function (exports) { return generator; }; - const is_object$1 = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); + const is_object$1 = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; let CsvError$1 = class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } }; - const normalize_columns_array = function(columns){ + const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object$1(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError$1('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object$1(column)) { + if (typeof column.name !== "string") { + throw new CsvError$1("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError$1('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError$1("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; - class ResizeableBuffer{ - constructor(size=100){ + class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer$1(val)){ + prepend(val) { + if (isBuffer$1(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -5538,44 +5559,44 @@ var csv = (function (exports) { val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -5590,7 +5611,7 @@ var csv = (function (exports) { const space = 32; const tab = 9; - const init_state = function(options){ + const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -5600,9 +5621,14 @@ var csv = (function (exports) { error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer$1(options.escape) && isBuffer$1(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer$1(options.escape) && + isBuffer$1(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -5620,454 +5646,700 @@ var csv = (function (exports) { record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; - const underscore$1 = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore$1 = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options$1 = function(opts){ + const normalize_options$1 = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore$1(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError$1('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError$1( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError$1('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError$1( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer$1(options.comment)){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer$1(options.comment)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer$1(delimiter) || delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer$1(delimiter) || delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer$1(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer$1(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError$1('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError$1( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError$1('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError$1( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer$1(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer$1(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer$1(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer$1(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer$1(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer$1(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer$1(rd)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer$1(rd)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; - const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); + const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -6078,21 +6350,21 @@ var csv = (function (exports) { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; - const transform$1 = function(original_options = {}) { + const transform$1 = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options$1(original_options); return { @@ -6100,10 +6372,11 @@ var csv = (function (exports) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -6113,55 +6386,73 @@ var csv = (function (exports) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options$1({...this.original_options, encoding: encoding}); + this.options = normalize_options$1({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -6170,51 +6461,62 @@ var csv = (function (exports) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -6222,74 +6524,122 @@ var csv = (function (exports) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError$1('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError$1('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError$1( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -6297,18 +6647,24 @@ var csv = (function (exports) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -6318,157 +6674,218 @@ var csv = (function (exports) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError$1('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError$1('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError$1('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError$1('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError$1('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError$1( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError$1( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -6479,45 +6896,53 @@ var csv = (function (exports) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -6525,19 +6950,28 @@ var csv = (function (exports) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError$1('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError$1( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -6545,92 +6979,98 @@ var csv = (function (exports) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -6644,46 +7084,53 @@ var csv = (function (exports) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -6691,13 +7138,13 @@ var csv = (function (exports) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -6705,32 +7152,32 @@ var csv = (function (exports) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -6740,168 +7187,197 @@ var csv = (function (exports) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; class Parser extends Transform { - constructor(opts = {}){ - super({...{readableObjectMode: true}, ...opts, encoding: null}); - this.api = transform$1({on_skip: (err, chunk) => { - this.emit('skip', err, chunk); - }, ...opts}); + constructor(opts = {}) { + super({ ...{ readableObjectMode: true }, ...opts, encoding: null }); + this.api = transform$1({ + on_skip: (err, chunk) => { + this.emit("skip", err, chunk); + }, + ...opts, + }); // Backward compatibility this.state = this.api.state; this.options = this.api.options; this.info = this.api.info; } // Implementation of `Transform._transform` - _transform(buf, _, callback){ - if(this.state.stop === true){ + _transform(buf, _, callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(buf, false, (record) => { - this.push(record); - }, () => { - this.push(null); - this.end(); - // Fix #333 and break #410 - // ko: api.stream.iterator.coffee - // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) - // ko: api.stream.finished # aborted (with Readable) - // this.destroy() - // Fix #410 and partially break #333 - // ok: api.stream.iterator.coffee - // ok: api.stream.finished # aborted (with generate()) - // broken: api.stream.finished # aborted (with Readable) - this.on('end', this.destroy); - }); - if(err !== undefined){ + const err = this.api.parse( + buf, + false, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.end(); + // Fix #333 and break #410 + // ko: api.stream.iterator.coffee + // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) + // ko: api.stream.finished # aborted (with Readable) + // this.destroy() + // Fix #410 and partially break #333 + // ok: api.stream.iterator.coffee + // ok: api.stream.finished # aborted (with generate()) + // broken: api.stream.finished # aborted (with Readable) + this.on("end", this.destroy); + }, + ); + if (err !== undefined) { this.state.stop = true; } callback(err); } // Implementation of `Transform._flush` - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(undefined, true, (record) => { - this.push(record); - }, () => { - this.push(null); - this.on('end', this.destroy); - }); + const err = this.api.parse( + undefined, + true, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.on("end", this.destroy); + }, + ); callback(err); } } - const parse = function(){ + const parse = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (typeof argument === 'string' || isBuffer$1(argument))){ + if ( + data === undefined && + (typeof argument === "string" || isBuffer$1(argument)) + ) { data = argument; - }else if(options === undefined && is_object$1(argument)){ + } else if (options === undefined && is_object$1(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError$1('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` - ], options || {}); + } else { + throw new CsvError$1( + "CSV_INVALID_ARGUMENT", + ["Invalid argument:", `got ${JSON.stringify(argument)} at index ${i}`], + options || {}, + ); } } const parser = new Parser(options); - if(callback){ - const records = options === undefined || options.objname === undefined ? [] : {}; - parser.on('readable', function(){ + if (callback) { + const records = + options === undefined || options.objname === undefined ? [] : {}; + parser.on("readable", function () { let record; - while((record = this.read()) !== null){ - if(options === undefined || options.objname === undefined){ + while ((record = this.read()) !== null) { + if (options === undefined || options.objname === undefined) { records.push(record); - }else { + } else { records[record[0]] = record[1]; } } }); - parser.on('error', function(err){ + parser.on("error", function (err) { callback(err, undefined, parser.api.__infoDataSet()); }); - parser.on('end', function(){ + parser.on("end", function () { callback(undefined, records, parser.api.__infoDataSet()); }); } - if(data !== undefined){ - const writer = function(){ + if (data !== undefined) { + const writer = function () { parser.write(data); parser.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } return parser; }; - const Transformer = function(options = {}, handler){ + /* + Stream Transform + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -6917,20 +7393,21 @@ var csv = (function (exports) { util.inherits(Transformer, Stream.Transform); - Transformer.prototype._transform = function(chunk, _, cb){ + Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -6942,108 +7419,111 @@ var csv = (function (exports) { } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; - Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ + Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; - Transformer.prototype.__done = function(err, chunks, cb){ + Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; - const transform = function(){ + const transform = function () { let options = {}; let callback, handler, records; - for(let i = 0; i< arguments.length; i++){ + for (let i = 0; i < arguments.length; i++) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { if (handler && i === arguments.length - 1) { callback = argument; } else { handler = argument; } - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } const transformer = new Transformer(options, handler); let error = false; if (records) { - const writer = function(){ - for(const record of records){ - if(error) break; + const writer = function () { + for (const record of records) { + if (error) break; transformer.write(record); } transformer.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } - if(callback || options.consume) { + if (callback || options.consume) { const result = []; - transformer.on('readable', function(){ - let record; while((record = transformer.read()) !== null){ - if(callback){ + transformer.on("readable", function () { + let record; + while ((record = transformer.read()) !== null) { + if (callback) { result.push(record); } } }); - transformer.on('error', function(err){ + transformer.on("error", function (err) { error = true; if (callback) callback(err); }); - transformer.on('end', function(){ + transformer.on("end", function () { if (callback && !error) callback(null, result); }); } @@ -7052,136 +7532,163 @@ var csv = (function (exports) { class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; // Lodash implementation of `get` - const charCodeOfDot = '.'.charCodeAt(0); + const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", + ); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; - const getTag = function(value){ + const getTag = function (value) { return Object.prototype.toString.call(value); }; - const isSymbol = function(value){ + const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; - const isKey = function(value, object){ - if(Array.isArray(value)){ + const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; - const stringToPath = function(string){ + const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; - const castPath = function(value, object){ - if(Array.isArray(value)){ + const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; - const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; + const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; - const get = function(object, path){ + const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; - const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ + const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -7189,238 +7696,288 @@ var csv = (function (exports) { return [undefined, columns]; }; - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts) { + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer$1(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer$1(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer$1(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer$1(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer$1(options.escape)){ + } else if (isBuffer$1(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer$1(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer$1(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); - const stringifier = function(options, state, info){ + const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -7429,96 +7986,136 @@ var csv = (function (exports) { this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -7528,171 +8125,190 @@ var csv = (function (exports) { // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; + /* + CSV Stringify + + Please look at the [project documentation](https://csv.js.org/stringify/) for + additional information. + */ + + class Stringifier extends Transform { - constructor(opts = {}){ - super({...{writableObjectMode: true}, ...opts}); + constructor(opts = {}) { + super({ ...{ writableObjectMode: true }, ...opts }); const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; // Expose options this.options = options; // Internal state this.state = { - stop: false + stop: false, }; // Information this.info = { - records: 0 + records: 0, }; this.api = stringifier(this.options, this.state, this.info); this.api.options.on_record = (...args) => { - this.emit('record', ...args); + this.emit("record", ...args); }; } - _transform(chunk, encoding, callback){ - if(this.state.stop === true){ + _transform(chunk, encoding, callback) { + if (this.state.stop === true) { return; } const err = this.api.__transform(chunk, this.push.bind(this)); - if(err !== undefined){ + if (err !== undefined) { this.state.stop = true; } callback(err); } - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { // Note, Node.js 12 call flush even after an error, we must prevent // `callback` from being called in flush without any error. return; } - if(this.info.records === 0){ + if (this.info.records === 0) { this.api.bom(this.push.bind(this)); const err = this.api.headers(this.push.bind(this)); - if(err) callback(err); + if (err) callback(err); } callback(); } } - const stringify = function(){ + const stringify = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (Array.isArray(argument))){ + if (data === undefined && Array.isArray(argument)) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` + } else { + throw new CsvError("CSV_INVALID_ARGUMENT", [ + "Invalid argument:", + `got ${JSON.stringify(argument)} at index ${i}`, ]); } } const stringifier = new Stringifier(options); - if(callback){ + if (callback) { const chunks = []; - stringifier.on('readable', function(){ + stringifier.on("readable", function () { let chunk; - while((chunk = this.read()) !== null){ + while ((chunk = this.read()) !== null) { chunks.push(chunk); } }); - stringifier.on('error', function(err){ + stringifier.on("error", function (err) { callback(err); }); - stringifier.on('end', function(){ + stringifier.on("end", function () { try { - callback(undefined, chunks.join('')); + callback(undefined, chunks.join("")); } catch (err) { // This can happen if the `chunks` is extremely long; it may throw // "Cannot create a string longer than 0x1fffffe8 characters" @@ -7702,17 +8318,17 @@ var csv = (function (exports) { } }); } - if(data !== undefined){ - const writer = function(){ - for(const record of data){ + if (data !== undefined) { + const writer = function () { + for (const record of data) { stringifier.write(record); } stringifier.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv/dist/iife/sync.js b/packages/csv/dist/iife/sync.js index 0ad11fa0c..37868b5cb 100644 --- a/packages/csv/dist/iife/sync.js +++ b/packages/csv/dist/iife/sync.js @@ -2003,7 +2003,7 @@ var csv_sync = (function (exports) { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5201,54 +5201,54 @@ var csv_sync = (function (exports) { // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. - const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { + const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5257,13 +5257,13 @@ var csv_sync = (function (exports) { // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5271,28 +5271,32 @@ var csv_sync = (function (exports) { fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5307,7 +5311,7 @@ var csv_sync = (function (exports) { // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5337,48 +5341,54 @@ var csv_sync = (function (exports) { // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5387,7 +5397,7 @@ var csv_sync = (function (exports) { } }; - const Generator = function(options = {}){ + const Generator = function (options = {}) { this.options = normalize_options$2(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5397,131 +5407,149 @@ var csv_sync = (function (exports) { util.inherits(Generator, Stream.Readable); // Stop the generation. - Generator.prototype.end = function(){ + Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. - Generator.prototype._read = function(size){ + Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; - Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); + Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. - Generator.prototype.__push = function(record){ + Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; - const generate = function(options){ - if(typeof options === 'string' && /\d+/.test(options)){ + /* + CSV Generate - sync module + + Please look at the [project documentation](https://csv.js.org/generate/) for + additional information. + */ + + + const generate = function (options) { + if (typeof options === "string" && /\d+/.test(options)) { options = parseInt(options); } - if(Number.isInteger(options)){ - options = {length: options}; - }else if(typeof options !== 'object' || options === null){ - throw Error('Invalid Argument: options must be an object or an integer'); + if (Number.isInteger(options)) { + options = { length: options }; + } else if (typeof options !== "object" || options === null) { + throw Error("Invalid Argument: options must be an object or an integer"); } - if(!Number.isInteger(options.length)){ - throw Error('Invalid Argument: length is not defined'); + if (!Number.isInteger(options.length)) { + throw Error("Invalid Argument: length is not defined"); } const chunks = []; let work = true; const generator = new Generator(options); - generator.push = function(chunk){ - if(chunk === null){ - return work = false; + generator.push = function (chunk) { + if (chunk === null) { + return (work = false); } - chunks.push(chunk); + chunks.push(chunk); }; - while(work){ + while (work) { generator.__read(options.highWaterMark); } - if(!options.objectMode){ - return chunks.join(''); - }else { + if (!options.objectMode) { + return chunks.join(""); + } else { return chunks; } }; let CsvError$1 = class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } }; - const is_object$1 = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); + const is_object$1 = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; - const normalize_columns_array = function(columns){ + const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object$1(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError$1('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object$1(column)) { + if (typeof column.name !== "string") { + throw new CsvError$1("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError$1('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError$1("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; - class ResizeableBuffer{ - constructor(size=100){ + class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer$1(val)){ + prepend(val) { + if (isBuffer$1(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -5529,44 +5557,44 @@ var csv_sync = (function (exports) { val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -5581,7 +5609,7 @@ var csv_sync = (function (exports) { const space = 32; const tab = 9; - const init_state = function(options){ + const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -5591,9 +5619,14 @@ var csv_sync = (function (exports) { error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer$1(options.escape) && isBuffer$1(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer$1(options.escape) && + isBuffer$1(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -5611,454 +5644,700 @@ var csv_sync = (function (exports) { record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; - const underscore$1 = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore$1 = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options$1 = function(opts){ + const normalize_options$1 = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore$1(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError$1('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError$1( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError$1('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError$1( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer$1(options.comment)){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer$1(options.comment)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer$1(delimiter) || delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer$1(delimiter) || delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer$1(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer$1(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError$1('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError$1( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError$1('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError$1( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer$1(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer$1(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer$1(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer$1(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer$1(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer$1(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer$1(rd)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer$1(rd)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; - const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); + const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -6069,21 +6348,21 @@ var csv_sync = (function (exports) { // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; - const transform$1 = function(original_options = {}) { + const transform$1 = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options$1(original_options); return { @@ -6091,10 +6370,11 @@ var csv_sync = (function (exports) { original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -6104,55 +6384,73 @@ var csv_sync = (function (exports) { // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options$1({...this.original_options, encoding: encoding}); + this.options = normalize_options$1({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -6161,51 +6459,62 @@ var csv_sync = (function (exports) { } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -6213,74 +6522,122 @@ var csv_sync = (function (exports) { } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError$1('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError$1('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError$1( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -6288,18 +6645,24 @@ var csv_sync = (function (exports) { continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -6309,157 +6672,218 @@ var csv_sync = (function (exports) { pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError$1('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError$1('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError$1('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError$1('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError$1('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError$1( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError$1( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -6470,45 +6894,53 @@ var csv_sync = (function (exports) { } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -6516,19 +6948,28 @@ var csv_sync = (function (exports) { } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError$1('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError$1( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -6536,92 +6977,98 @@ var csv_sync = (function (exports) { this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -6635,46 +7082,53 @@ var csv_sync = (function (exports) { // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -6682,13 +7136,13 @@ var csv_sync = (function (exports) { } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -6696,32 +7150,32 @@ var csv_sync = (function (exports) { } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -6731,189 +7185,214 @@ var csv_sync = (function (exports) { } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; - const parse = function(data, opts={}){ - if(typeof data === 'string'){ + const parse = function (data, opts = {}) { + if (typeof data === "string") { data = Buffer.from(data); } const records = opts && opts.objname ? {} : []; const parser = transform$1(opts); const push = (record) => { - if(parser.options.objname === undefined) - records.push(record); + if (parser.options.objname === undefined) records.push(record); else { records[record[0]] = record[1]; } }; const close = () => {}; const err1 = parser.parse(data, false, push, close); - if(err1 !== undefined) throw err1; + if (err1 !== undefined) throw err1; const err2 = parser.parse(undefined, true, push, close); - if(err2 !== undefined) throw err2; + if (err2 !== undefined) throw err2; return records; }; // Lodash implementation of `get` - const charCodeOfDot = '.'.charCodeAt(0); + const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", + ); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; - const getTag = function(value){ + const getTag = function (value) { return Object.prototype.toString.call(value); }; - const isSymbol = function(value){ + const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; - const isKey = function(value, object){ - if(Array.isArray(value)){ + const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; - const stringToPath = function(string){ + const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; - const castPath = function(value, object){ - if(Array.isArray(value)){ + const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; - const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; + const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; - const get = function(object, path){ + const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; - const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; - const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ + const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -6923,253 +7402,307 @@ var csv_sync = (function (exports) { class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts) { + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer$1(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer$1(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer$1(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer$1(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer$1(options.escape)){ + } else if (isBuffer$1(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer$1(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer$1(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); - const stringifier = function(options, state, info){ + const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -7178,96 +7711,136 @@ var csv_sync = (function (exports) { this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -7277,133 +7850,152 @@ var csv_sync = (function (exports) { // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; - const stringify = function(records, opts={}){ + const stringify = function (records, opts = {}) { const data = []; const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; const state = { - stop: false + stop: false, }; // Information const info = { - records: 0 + records: 0, }; const api = stringifier(options, state, info); - for(const record of records){ - const err = api.__transform(record, function(record){ + for (const record of records) { + const err = api.__transform(record, function (record) { data.push(record); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - if(data.length === 0){ + if (data.length === 0) { api.bom((d) => { data.push(d); }); const err = api.headers((headers) => { data.push(headers); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - return data.join(''); + return data.join(""); }; - const Transformer = function(options = {}, handler){ + /* + Stream Transform + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -7419,20 +8011,21 @@ var csv_sync = (function (exports) { util.inherits(Transformer, Stream.Transform); - Transformer.prototype._transform = function(chunk, _, cb){ + Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -7444,93 +8037,103 @@ var csv_sync = (function (exports) { } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; - Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ + Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; - Transformer.prototype.__done = function(err, chunks, cb){ + Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; - const transform = function(){ + /* + Stream Transform - sync module + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const transform = function () { // Import arguments normalization let handler, records; let options = {}; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { handler = argument; - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } // Validate arguments let expected_handler_length = 1; - if(options.params){ + if (options.params) { expected_handler_length++; } - if(handler.length > expected_handler_length){ - throw Error('Invalid Handler: only synchonous handlers are supported'); + if (handler.length > expected_handler_length) { + throw Error("Invalid Handler: only synchonous handlers are supported"); } // Start transformation const chunks = []; const transformer = new Transformer(options, handler); - transformer.push = function(chunk){ + transformer.push = function (chunk) { chunks.push(chunk); }; - for(const record of records){ - transformer._transform(record, null, function(){}); + for (const record of records) { + transformer._transform(record, null, function () {}); } - return chunks; + return chunks; }; exports.generate = generate; diff --git a/packages/csv/dist/umd/index.js b/packages/csv/dist/umd/index.js index 97259326c..434f07055 100644 --- a/packages/csv/dist/umd/index.js +++ b/packages/csv/dist/umd/index.js @@ -2006,7 +2006,7 @@ this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5204,54 +5204,54 @@ // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. - const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { + const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5260,13 +5260,13 @@ // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5274,28 +5274,32 @@ fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5310,7 +5314,7 @@ // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5340,48 +5344,54 @@ // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5390,7 +5400,7 @@ } }; - const Generator = function(options = {}){ + const Generator = function (options = {}) { this.options = normalize_options$2(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5400,70 +5410,77 @@ util.inherits(Generator, Stream.Readable); // Stop the generation. - Generator.prototype.end = function(){ + Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. - Generator.prototype._read = function(size){ + Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; - Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); + Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. - Generator.prototype.__push = function(record){ + Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; - const generate = function(){ + const generate = function () { let options; let callback; - if(arguments.length === 2){ + if (arguments.length === 2) { options = arguments[0]; callback = arguments[1]; - }else if(arguments.length === 1){ - if(typeof arguments[0] === 'function'){ + } else if (arguments.length === 1) { + if (typeof arguments[0] === "function") { options = {}; callback = arguments[0]; - }else { + } else { options = arguments[0]; } - }else if(arguments.length === 0){ + } else if (arguments.length === 0) { options = {}; } const generator = new Generator(options); - if(callback){ + if (callback) { const data = []; - generator.on('readable', function(){ - let d; while((d = generator.read()) !== null){ + generator.on("readable", function () { + let d; + while ((d = generator.read()) !== null) { data.push(d); } }); - generator.on('error', callback); - generator.on('end', function(){ - if(generator.options.objectMode){ + generator.on("error", callback); + generator.on("end", function () { + if (generator.options.objectMode) { callback(null, data); - }else { - if(generator.options.encoding){ - callback(null, data.join('')); - }else { + } else { + if (generator.options.encoding) { + callback(null, data.join("")); + } else { callback(null, Buffer.concat(data)); } } @@ -5472,68 +5489,72 @@ return generator; }; - const is_object$1 = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); + const is_object$1 = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; let CsvError$1 = class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } }; - const normalize_columns_array = function(columns){ + const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object$1(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError$1('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object$1(column)) { + if (typeof column.name !== "string") { + throw new CsvError$1("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError$1('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError$1("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; - class ResizeableBuffer{ - constructor(size=100){ + class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer$1(val)){ + prepend(val) { + if (isBuffer$1(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -5541,44 +5562,44 @@ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -5593,7 +5614,7 @@ const space = 32; const tab = 9; - const init_state = function(options){ + const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -5603,9 +5624,14 @@ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer$1(options.escape) && isBuffer$1(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer$1(options.escape) && + isBuffer$1(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -5623,454 +5649,700 @@ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; - const underscore$1 = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore$1 = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options$1 = function(opts){ + const normalize_options$1 = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore$1(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError$1('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError$1( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError$1('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError$1( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer$1(options.comment)){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer$1(options.comment)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer$1(delimiter) || delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer$1(delimiter) || delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer$1(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer$1(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError$1('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError$1( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError$1('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError$1( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer$1(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer$1(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer$1(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer$1(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer$1(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer$1(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer$1(rd)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer$1(rd)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; - const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); + const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -6081,21 +6353,21 @@ // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; - const transform$1 = function(original_options = {}) { + const transform$1 = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options$1(original_options); return { @@ -6103,10 +6375,11 @@ original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -6116,55 +6389,73 @@ // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options$1({...this.original_options, encoding: encoding}); + this.options = normalize_options$1({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -6173,51 +6464,62 @@ } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -6225,74 +6527,122 @@ } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError$1('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError$1('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError$1( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -6300,18 +6650,24 @@ continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -6321,157 +6677,218 @@ pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError$1('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError$1('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError$1('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError$1('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError$1('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError$1( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError$1( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -6482,45 +6899,53 @@ } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -6528,19 +6953,28 @@ } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError$1('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError$1( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -6548,92 +6982,98 @@ this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -6647,46 +7087,53 @@ // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -6694,13 +7141,13 @@ } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -6708,32 +7155,32 @@ } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -6743,168 +7190,197 @@ } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; class Parser extends Transform { - constructor(opts = {}){ - super({...{readableObjectMode: true}, ...opts, encoding: null}); - this.api = transform$1({on_skip: (err, chunk) => { - this.emit('skip', err, chunk); - }, ...opts}); + constructor(opts = {}) { + super({ ...{ readableObjectMode: true }, ...opts, encoding: null }); + this.api = transform$1({ + on_skip: (err, chunk) => { + this.emit("skip", err, chunk); + }, + ...opts, + }); // Backward compatibility this.state = this.api.state; this.options = this.api.options; this.info = this.api.info; } // Implementation of `Transform._transform` - _transform(buf, _, callback){ - if(this.state.stop === true){ + _transform(buf, _, callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(buf, false, (record) => { - this.push(record); - }, () => { - this.push(null); - this.end(); - // Fix #333 and break #410 - // ko: api.stream.iterator.coffee - // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) - // ko: api.stream.finished # aborted (with Readable) - // this.destroy() - // Fix #410 and partially break #333 - // ok: api.stream.iterator.coffee - // ok: api.stream.finished # aborted (with generate()) - // broken: api.stream.finished # aborted (with Readable) - this.on('end', this.destroy); - }); - if(err !== undefined){ + const err = this.api.parse( + buf, + false, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.end(); + // Fix #333 and break #410 + // ko: api.stream.iterator.coffee + // ko with v21.4.0, ok with node v20.5.1: api.stream.finished # aborted (with generate()) + // ko: api.stream.finished # aborted (with Readable) + // this.destroy() + // Fix #410 and partially break #333 + // ok: api.stream.iterator.coffee + // ok: api.stream.finished # aborted (with generate()) + // broken: api.stream.finished # aborted (with Readable) + this.on("end", this.destroy); + }, + ); + if (err !== undefined) { this.state.stop = true; } callback(err); } // Implementation of `Transform._flush` - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { return; } - const err = this.api.parse(undefined, true, (record) => { - this.push(record); - }, () => { - this.push(null); - this.on('end', this.destroy); - }); + const err = this.api.parse( + undefined, + true, + (record) => { + this.push(record); + }, + () => { + this.push(null); + this.on("end", this.destroy); + }, + ); callback(err); } } - const parse = function(){ + const parse = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (typeof argument === 'string' || isBuffer$1(argument))){ + if ( + data === undefined && + (typeof argument === "string" || isBuffer$1(argument)) + ) { data = argument; - }else if(options === undefined && is_object$1(argument)){ + } else if (options === undefined && is_object$1(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError$1('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` - ], options || {}); + } else { + throw new CsvError$1( + "CSV_INVALID_ARGUMENT", + ["Invalid argument:", `got ${JSON.stringify(argument)} at index ${i}`], + options || {}, + ); } } const parser = new Parser(options); - if(callback){ - const records = options === undefined || options.objname === undefined ? [] : {}; - parser.on('readable', function(){ + if (callback) { + const records = + options === undefined || options.objname === undefined ? [] : {}; + parser.on("readable", function () { let record; - while((record = this.read()) !== null){ - if(options === undefined || options.objname === undefined){ + while ((record = this.read()) !== null) { + if (options === undefined || options.objname === undefined) { records.push(record); - }else { + } else { records[record[0]] = record[1]; } } }); - parser.on('error', function(err){ + parser.on("error", function (err) { callback(err, undefined, parser.api.__infoDataSet()); }); - parser.on('end', function(){ + parser.on("end", function () { callback(undefined, records, parser.api.__infoDataSet()); }); } - if(data !== undefined){ - const writer = function(){ + if (data !== undefined) { + const writer = function () { parser.write(data); parser.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } return parser; }; - const Transformer = function(options = {}, handler){ + /* + Stream Transform + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -6920,20 +7396,21 @@ util.inherits(Transformer, Stream.Transform); - Transformer.prototype._transform = function(chunk, _, cb){ + Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -6945,108 +7422,111 @@ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; - Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ + Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; - Transformer.prototype.__done = function(err, chunks, cb){ + Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; - const transform = function(){ + const transform = function () { let options = {}; let callback, handler, records; - for(let i = 0; i< arguments.length; i++){ + for (let i = 0; i < arguments.length; i++) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { if (handler && i === arguments.length - 1) { callback = argument; } else { handler = argument; } - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } const transformer = new Transformer(options, handler); let error = false; if (records) { - const writer = function(){ - for(const record of records){ - if(error) break; + const writer = function () { + for (const record of records) { + if (error) break; transformer.write(record); } transformer.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } - if(callback || options.consume) { + if (callback || options.consume) { const result = []; - transformer.on('readable', function(){ - let record; while((record = transformer.read()) !== null){ - if(callback){ + transformer.on("readable", function () { + let record; + while ((record = transformer.read()) !== null) { + if (callback) { result.push(record); } } }); - transformer.on('error', function(err){ + transformer.on("error", function (err) { error = true; if (callback) callback(err); }); - transformer.on('end', function(){ + transformer.on("end", function () { if (callback && !error) callback(null, result); }); } @@ -7055,136 +7535,163 @@ class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; // Lodash implementation of `get` - const charCodeOfDot = '.'.charCodeAt(0); + const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", + ); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; - const getTag = function(value){ + const getTag = function (value) { return Object.prototype.toString.call(value); }; - const isSymbol = function(value){ + const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; - const isKey = function(value, object){ - if(Array.isArray(value)){ + const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; - const stringToPath = function(string){ + const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; - const castPath = function(value, object){ - if(Array.isArray(value)){ + const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; - const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; + const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; - const get = function(object, path){ + const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; - const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ + const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -7192,238 +7699,288 @@ return [undefined, columns]; }; - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts) { + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer$1(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer$1(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer$1(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer$1(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer$1(options.escape)){ + } else if (isBuffer$1(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer$1(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer$1(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); - const stringifier = function(options, state, info){ + const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -7432,96 +7989,136 @@ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -7531,171 +8128,190 @@ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; + /* + CSV Stringify + + Please look at the [project documentation](https://csv.js.org/stringify/) for + additional information. + */ + + class Stringifier extends Transform { - constructor(opts = {}){ - super({...{writableObjectMode: true}, ...opts}); + constructor(opts = {}) { + super({ ...{ writableObjectMode: true }, ...opts }); const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; // Expose options this.options = options; // Internal state this.state = { - stop: false + stop: false, }; // Information this.info = { - records: 0 + records: 0, }; this.api = stringifier(this.options, this.state, this.info); this.api.options.on_record = (...args) => { - this.emit('record', ...args); + this.emit("record", ...args); }; } - _transform(chunk, encoding, callback){ - if(this.state.stop === true){ + _transform(chunk, encoding, callback) { + if (this.state.stop === true) { return; } const err = this.api.__transform(chunk, this.push.bind(this)); - if(err !== undefined){ + if (err !== undefined) { this.state.stop = true; } callback(err); } - _flush(callback){ - if(this.state.stop === true){ + _flush(callback) { + if (this.state.stop === true) { // Note, Node.js 12 call flush even after an error, we must prevent // `callback` from being called in flush without any error. return; } - if(this.info.records === 0){ + if (this.info.records === 0) { this.api.bom(this.push.bind(this)); const err = this.api.headers(this.push.bind(this)); - if(err) callback(err); + if (err) callback(err); } callback(); } } - const stringify = function(){ + const stringify = function () { let data, options, callback; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; - if(data === undefined && (Array.isArray(argument))){ + if (data === undefined && Array.isArray(argument)) { data = argument; - }else if(options === undefined && is_object(argument)){ + } else if (options === undefined && is_object(argument)) { options = argument; - }else if(callback === undefined && type === 'function'){ + } else if (callback === undefined && type === "function") { callback = argument; - }else { - throw new CsvError('CSV_INVALID_ARGUMENT', [ - 'Invalid argument:', - `got ${JSON.stringify(argument)} at index ${i}` + } else { + throw new CsvError("CSV_INVALID_ARGUMENT", [ + "Invalid argument:", + `got ${JSON.stringify(argument)} at index ${i}`, ]); } } const stringifier = new Stringifier(options); - if(callback){ + if (callback) { const chunks = []; - stringifier.on('readable', function(){ + stringifier.on("readable", function () { let chunk; - while((chunk = this.read()) !== null){ + while ((chunk = this.read()) !== null) { chunks.push(chunk); } }); - stringifier.on('error', function(err){ + stringifier.on("error", function (err) { callback(err); }); - stringifier.on('end', function(){ + stringifier.on("end", function () { try { - callback(undefined, chunks.join('')); + callback(undefined, chunks.join("")); } catch (err) { // This can happen if the `chunks` is extremely long; it may throw // "Cannot create a string longer than 0x1fffffe8 characters" @@ -7705,17 +8321,17 @@ } }); } - if(data !== undefined){ - const writer = function(){ - for(const record of data){ + if (data !== undefined) { + const writer = function () { + for (const record of data) { stringifier.write(record); } stringifier.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } diff --git a/packages/csv/dist/umd/sync.js b/packages/csv/dist/umd/sync.js index 840c513e7..95d609b9c 100644 --- a/packages/csv/dist/umd/sync.js +++ b/packages/csv/dist/umd/sync.js @@ -2006,7 +2006,7 @@ this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5204,54 +5204,54 @@ // State return { start_time: options.duration ? Date.now() : null, - fixed_size_buffer: '', + fixed_size_buffer: "", count_written: 0, count_created: 0, }; }; // Generate a random number between 0 and 1 with 2 decimals. The function is idempotent if it detect the "seed" option. - const random = function(options={}){ - if(options.seed){ - return options.seed = options.seed * Math.PI * 100 % 100 / 100; - }else { + const random = function (options = {}) { + if (options.seed) { + return (options.seed = ((options.seed * Math.PI * 100) % 100) / 100); + } else { return Math.random(); } }; const types = { // Generate an ASCII value. - ascii: function({options}){ + ascii: function ({ options }) { const column = []; const nb_chars = Math.ceil(random(options) * options.maxWordLength); - for(let i=0; i { // Convert Stream Readable options if underscored - if(opts.object_mode){ + if (opts.object_mode) { opts.objectMode = opts.object_mode; } - if(opts.high_water_mark){ + if (opts.high_water_mark) { opts.highWaterMark = opts.high_water_mark; } // See https://nodejs.org/api/stream.html#stream_new_stream_readable_options @@ -5260,13 +5260,13 @@ // opts.highWaterMark = opts.highWaterMark ?? stream.getDefaultHighWaterMark(opts.objectMode); // Clone and camelize options const options = {}; - for(const k in opts){ + for (const k in opts) { options[camelize(k)] = opts[k]; } // Normalize options const dft = { columns: 8, - delimiter: ',', + delimiter: ",", duration: null, encoding: null, end: null, @@ -5274,28 +5274,32 @@ fixedSize: false, length: -1, maxWordLength: 16, - rowDelimiter: '\n', + rowDelimiter: "\n", seed: false, sleep: 0, }; - for(const k in dft){ - if(options[k] === undefined){ + for (const k in dft) { + if (options[k] === undefined) { options[k] = dft[k]; } } // Default values - if(options.eof === true){ + if (options.eof === true) { options.eof = options.rowDelimiter; } - if(typeof options.columns === 'number'){ + if (typeof options.columns === "number") { options.columns = new Array(options.columns); } - const accepted_header_types = Object.keys(types).filter((t) => (!['super_', 'camelize'].includes(t))); - for(let i = 0; i < options.columns.length; i++){ - const v = options.columns[i] || 'ascii'; - if(typeof v === 'string'){ - if(!accepted_header_types.includes(v)){ - throw Error(`Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`); + const accepted_header_types = Object.keys(types).filter( + (t) => !["super_", "camelize"].includes(t), + ); + for (let i = 0; i < options.columns.length; i++) { + const v = options.columns[i] || "ascii"; + if (typeof v === "string") { + if (!accepted_header_types.includes(v)) { + throw Error( + `Invalid column type: got "${v}", default values are ${JSON.stringify(accepted_header_types)}`, + ); } options.columns[i] = types[v]; } @@ -5310,7 +5314,7 @@ // Get remaining buffer when fixedSize is enable if (options.fixedSize) { recordsLength = state.fixed_size_buffer.length; - if(recordsLength !== 0){ + if (recordsLength !== 0) { data.push(state.fixed_size_buffer); } } @@ -5340,48 +5344,54 @@ // Create the record let record = []; let recordLength; - for(const fn of options.columns){ - const result = fn({options: options, state: state}); + for (const fn of options.columns) { + const result = fn({ options: options, state: state }); const type = typeof result; - if(result !== null && type !== 'string' && type !== 'number'){ - close(Error([ - 'INVALID_VALUE:', - 'values returned by column function must be', - 'a string, a number or null,', - `got ${JSON.stringify(result)}` - ].join(' '))); + if (result !== null && type !== "string" && type !== "number") { + close( + Error( + [ + "INVALID_VALUE:", + "values returned by column function must be", + "a string, a number or null,", + `got ${JSON.stringify(result)}`, + ].join(" "), + ), + ); return; } record.push(result); } // Obtain record length - if(options.objectMode){ + if (options.objectMode) { recordLength = 0; // recordLength is currently equal to the number of columns // This is wrong and shall equal to 1 record only - for(const column of record){ + for (const column of record) { recordLength += column.length; } - }else { + } else { // Stringify the record - record = (state.count_created === 0 ? '' : options.rowDelimiter)+record.join(options.delimiter); + record = + (state.count_created === 0 ? "" : options.rowDelimiter) + + record.join(options.delimiter); recordLength = record.length; } state.count_created++; - if(recordsLength + recordLength > size){ - if(options.objectMode){ + if (recordsLength + recordLength > size) { + if (options.objectMode) { data.push(record); - for(const record of data){ + for (const record of data) { push(record); } - }else { - if(options.fixedSize){ + } else { + if (options.fixedSize) { state.fixed_size_buffer = record.substr(size - recordsLength); data.push(record.substr(0, size - recordsLength)); - }else { + } else { data.push(record); } - push(data.join('')); + push(data.join("")); } return; } @@ -5390,7 +5400,7 @@ } }; - const Generator = function(options = {}){ + const Generator = function (options = {}) { this.options = normalize_options$2(options); // Call parent constructor Stream.Readable.call(this, this.options); @@ -5400,131 +5410,149 @@ util.inherits(Generator, Stream.Readable); // Stop the generation. - Generator.prototype.end = function(){ + Generator.prototype.end = function () { this.push(null); }; // Put new data into the read queue. - Generator.prototype._read = function(size){ + Generator.prototype._read = function (size) { setImmediate(() => { this.__read(size); }); }; - Generator.prototype.__read = function(size){ - read(this.options, this.state, size, (chunk) => { - this.__push(chunk); - }, (err) => { - if(err){ - this.destroy(err); - }else { - this.push(null); - } - }); + Generator.prototype.__read = function (size) { + read( + this.options, + this.state, + size, + (chunk) => { + this.__push(chunk); + }, + (err) => { + if (err) { + this.destroy(err); + } else { + this.push(null); + } + }, + ); }; // Put new data into the read queue. - Generator.prototype.__push = function(record){ + Generator.prototype.__push = function (record) { const push = () => { this.state.count_written++; this.push(record); - if(this.state.end === true){ + if (this.state.end === true) { return this.push(null); } }; this.options.sleep > 0 ? setTimeout(push, this.options.sleep) : push(); }; - const generate = function(options){ - if(typeof options === 'string' && /\d+/.test(options)){ + /* + CSV Generate - sync module + + Please look at the [project documentation](https://csv.js.org/generate/) for + additional information. + */ + + + const generate = function (options) { + if (typeof options === "string" && /\d+/.test(options)) { options = parseInt(options); } - if(Number.isInteger(options)){ - options = {length: options}; - }else if(typeof options !== 'object' || options === null){ - throw Error('Invalid Argument: options must be an object or an integer'); + if (Number.isInteger(options)) { + options = { length: options }; + } else if (typeof options !== "object" || options === null) { + throw Error("Invalid Argument: options must be an object or an integer"); } - if(!Number.isInteger(options.length)){ - throw Error('Invalid Argument: length is not defined'); + if (!Number.isInteger(options.length)) { + throw Error("Invalid Argument: length is not defined"); } const chunks = []; let work = true; const generator = new Generator(options); - generator.push = function(chunk){ - if(chunk === null){ - return work = false; + generator.push = function (chunk) { + if (chunk === null) { + return (work = false); } - chunks.push(chunk); + chunks.push(chunk); }; - while(work){ + while (work) { generator.__read(options.highWaterMark); } - if(!options.objectMode){ - return chunks.join(''); - }else { + if (!options.objectMode) { + return chunks.join(""); + } else { return chunks; } }; let CsvError$1 = class CsvError extends Error { constructor(code, message, options, ...contexts) { - if(Array.isArray(message)) message = message.join(' ').trim(); + if (Array.isArray(message)) message = message.join(" ").trim(); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString(options.encoding) + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } }; - const is_object$1 = function(obj){ - return (typeof obj === 'object' && obj !== null && !Array.isArray(obj)); + const is_object$1 = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; - const normalize_columns_array = function(columns){ + const normalize_columns_array = function (columns) { const normalizedColumns = []; - for(let i = 0, l = columns.length; i < l; i++){ + for (let i = 0, l = columns.length; i < l; i++) { const column = columns[i]; - if(column === undefined || column === null || column === false){ + if (column === undefined || column === null || column === false) { normalizedColumns[i] = { disabled: true }; - }else if(typeof column === 'string'){ + } else if (typeof column === "string") { normalizedColumns[i] = { name: column }; - }else if(is_object$1(column)){ - if(typeof column.name !== 'string'){ - throw new CsvError$1('CSV_OPTION_COLUMNS_MISSING_NAME', [ - 'Option columns missing name:', + } else if (is_object$1(column)) { + if (typeof column.name !== "string") { + throw new CsvError$1("CSV_OPTION_COLUMNS_MISSING_NAME", [ + "Option columns missing name:", `property "name" is required at position ${i}`, - 'when column is an object literal' + "when column is an object literal", ]); } normalizedColumns[i] = column; - }else { - throw new CsvError$1('CSV_INVALID_COLUMN_DEFINITION', [ - 'Invalid column definition:', - 'expect a string or a literal object,', - `got ${JSON.stringify(column)} at position ${i}` + } else { + throw new CsvError$1("CSV_INVALID_COLUMN_DEFINITION", [ + "Invalid column definition:", + "expect a string or a literal object,", + `got ${JSON.stringify(column)} at position ${i}`, ]); } } return normalizedColumns; }; - class ResizeableBuffer{ - constructor(size=100){ + class ResizeableBuffer { + constructor(size = 100) { this.size = size; this.length = 0; this.buf = Buffer.allocUnsafe(size); } - prepend(val){ - if(isBuffer$1(val)){ + prepend(val) { + if (isBuffer$1(val)) { const length = this.length + val.length; - if(length >= this.size){ + if (length >= this.size) { this.resize(); - if(length >= this.size){ - throw Error('INVALID_BUFFER_STATE'); + if (length >= this.size) { + throw Error("INVALID_BUFFER_STATE"); } } const buf = this.buf; @@ -5532,44 +5560,44 @@ val.copy(this.buf, 0); buf.copy(this.buf, val.length); this.length += val.length; - }else { + } else { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } const buf = this.clone(); this.buf[0] = val; - buf.copy(this.buf,1, 0, length); + buf.copy(this.buf, 1, 0, length); } } - append(val){ + append(val) { const length = this.length++; - if(length === this.size){ + if (length === this.size) { this.resize(); } this.buf[length] = val; } - clone(){ + clone() { return Buffer.from(this.buf.slice(0, this.length)); } - resize(){ + resize() { const length = this.length; this.size = this.size * 2; const buf = Buffer.allocUnsafe(this.size); - this.buf.copy(buf,0, 0, length); + this.buf.copy(buf, 0, 0, length); this.buf = buf; } - toString(encoding){ - if(encoding){ + toString(encoding) { + if (encoding) { return this.buf.slice(0, this.length).toString(encoding); - }else { + } else { return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length)); } } - toJSON(){ - return this.toString('utf8'); + toJSON() { + return this.toString("utf8"); } - reset(){ + reset() { this.length = 0; } } @@ -5584,7 +5612,7 @@ const space = 32; const tab = 9; - const init_state = function(options){ + const init_state = function (options) { return { bomSkipped: false, bufBytesStart: 0, @@ -5594,9 +5622,14 @@ error: undefined, enabled: options.from_line === 1, escaping: false, - escapeIsQuote: isBuffer$1(options.escape) && isBuffer$1(options.quote) && Buffer.compare(options.escape, options.quote) === 0, + escapeIsQuote: + isBuffer$1(options.escape) && + isBuffer$1(options.quote) && + Buffer.compare(options.escape, options.quote) === 0, // columns can be `false`, `true`, `Array` - expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined, + expectedRecordLength: Array.isArray(options.columns) + ? options.columns.length + : undefined, field: new ResizeableBuffer(20), firstLineToHeaders: options.cast_first_line_to_header, needMoreDataSize: Math.max( @@ -5614,454 +5647,700 @@ record: [], recordHasError: false, record_length: 0, - recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 0 : Math.max(...options.record_delimiter.map((v) => v.length)), - trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]], + recordDelimiterMaxLength: + options.record_delimiter.length === 0 + ? 0 + : Math.max(...options.record_delimiter.map((v) => v.length)), + trimChars: [ + Buffer.from(" ", options.encoding)[0], + Buffer.from("\t", options.encoding)[0], + ], wasQuoting: false, wasRowDelimiter: false, timchars: [ - Buffer.from(Buffer.from([cr$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([nl$1], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([np], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([space], 'utf8').toString(), options.encoding), - Buffer.from(Buffer.from([tab], 'utf8').toString(), options.encoding), - ] + Buffer.from(Buffer.from([cr$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([nl$1], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([np], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([space], "utf8").toString(), options.encoding), + Buffer.from(Buffer.from([tab], "utf8").toString(), options.encoding), + ], }; }; - const underscore$1 = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore$1 = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options$1 = function(opts){ + const normalize_options$1 = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore$1(opt)] = opts[opt]; } // Normalize option `encoding` // Note: defined first because other options depends on it // to convert chars/strings into buffers. - if(options.encoding === undefined || options.encoding === true){ - options.encoding = 'utf8'; - }else if(options.encoding === null || options.encoding === false){ + if (options.encoding === undefined || options.encoding === true) { + options.encoding = "utf8"; + } else if (options.encoding === null || options.encoding === false) { options.encoding = null; - }else if(typeof options.encoding !== 'string' && options.encoding !== null){ - throw new CsvError$1('CSV_INVALID_OPTION_ENCODING', [ - 'Invalid option encoding:', - 'encoding must be a string or null to return a buffer,', - `got ${JSON.stringify(options.encoding)}` - ], options); + } else if ( + typeof options.encoding !== "string" && + options.encoding !== null + ) { + throw new CsvError$1( + "CSV_INVALID_OPTION_ENCODING", + [ + "Invalid option encoding:", + "encoding must be a string or null to return a buffer,", + `got ${JSON.stringify(options.encoding)}`, + ], + options, + ); } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_BOM', [ - 'Invalid option bom:', 'bom must be true,', - `got ${JSON.stringify(options.bom)}` - ], options); + } else if (options.bom !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_BOM", + [ + "Invalid option bom:", + "bom must be true,", + `got ${JSON.stringify(options.bom)}`, + ], + options, + ); } // Normalize option `cast` options.cast_function = null; - if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){ + if ( + options.cast === undefined || + options.cast === null || + options.cast === false || + options.cast === "" + ) { options.cast = undefined; - }else if(typeof options.cast === 'function'){ + } else if (typeof options.cast === "function") { options.cast_function = options.cast; options.cast = true; - }else if(options.cast !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST', [ - 'Invalid option cast:', 'cast must be true or a function,', - `got ${JSON.stringify(options.cast)}` - ], options); + } else if (options.cast !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST", + [ + "Invalid option cast:", + "cast must be true or a function,", + `got ${JSON.stringify(options.cast)}`, + ], + options, + ); } // Normalize option `cast_date` - if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){ + if ( + options.cast_date === undefined || + options.cast_date === null || + options.cast_date === false || + options.cast_date === "" + ) { options.cast_date = false; - }else if(options.cast_date === true){ - options.cast_date = function(value){ + } else if (options.cast_date === true) { + options.cast_date = function (value) { const date = Date.parse(value); return !isNaN(date) ? new Date(date) : value; }; - }else if (typeof options.cast_date !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_CAST_DATE', [ - 'Invalid option cast_date:', 'cast_date must be true or a function,', - `got ${JSON.stringify(options.cast_date)}` - ], options); + } else if (typeof options.cast_date !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_CAST_DATE", + [ + "Invalid option cast_date:", + "cast_date must be true or a function,", + `got ${JSON.stringify(options.cast_date)}`, + ], + options, + ); } // Normalize option `columns` options.cast_first_line_to_header = null; - if(options.columns === true){ + if (options.columns === true) { // Fields in the first line are converted as-is to columns options.cast_first_line_to_header = undefined; - }else if(typeof options.columns === 'function'){ + } else if (typeof options.columns === "function") { options.cast_first_line_to_header = options.columns; options.columns = true; - }else if(Array.isArray(options.columns)){ + } else if (Array.isArray(options.columns)) { options.columns = normalize_columns_array(options.columns); - }else if(options.columns === undefined || options.columns === null || options.columns === false){ + } else if ( + options.columns === undefined || + options.columns === null || + options.columns === false + ) { options.columns = false; - }else { - throw new CsvError$1('CSV_INVALID_OPTION_COLUMNS', [ - 'Invalid option columns:', - 'expect an array, a function or true,', - `got ${JSON.stringify(options.columns)}` - ], options); + } else { + throw new CsvError$1( + "CSV_INVALID_OPTION_COLUMNS", + [ + "Invalid option columns:", + "expect an array, a function or true,", + `got ${JSON.stringify(options.columns)}`, + ], + options, + ); } // Normalize option `group_columns_by_name` - if(options.group_columns_by_name === undefined || options.group_columns_by_name === null || options.group_columns_by_name === false){ + if ( + options.group_columns_by_name === undefined || + options.group_columns_by_name === null || + options.group_columns_by_name === false + ) { options.group_columns_by_name = false; - }else if(options.group_columns_by_name !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'expect an boolean,', - `got ${JSON.stringify(options.group_columns_by_name)}` - ], options); - }else if(options.columns === false){ - throw new CsvError$1('CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME', [ - 'Invalid option group_columns_by_name:', - 'the `columns` mode must be activated.' - ], options); + } else if (options.group_columns_by_name !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "expect an boolean,", + `got ${JSON.stringify(options.group_columns_by_name)}`, + ], + options, + ); + } else if (options.columns === false) { + throw new CsvError$1( + "CSV_INVALID_OPTION_GROUP_COLUMNS_BY_NAME", + [ + "Invalid option group_columns_by_name:", + "the `columns` mode must be activated.", + ], + options, + ); } // Normalize option `comment` - if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){ + if ( + options.comment === undefined || + options.comment === null || + options.comment === false || + options.comment === "" + ) { options.comment = null; - }else { - if(typeof options.comment === 'string'){ + } else { + if (typeof options.comment === "string") { options.comment = Buffer.from(options.comment, options.encoding); } - if(!isBuffer$1(options.comment)){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment:', - 'comment must be a buffer or a string,', - `got ${JSON.stringify(options.comment)}` - ], options); + if (!isBuffer$1(options.comment)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment:", + "comment must be a buffer or a string,", + `got ${JSON.stringify(options.comment)}`, + ], + options, + ); } } // Normalize option `comment_no_infix` - if(options.comment_no_infix === undefined || options.comment_no_infix === null || options.comment_no_infix === false){ + if ( + options.comment_no_infix === undefined || + options.comment_no_infix === null || + options.comment_no_infix === false + ) { options.comment_no_infix = false; - }else if(options.comment_no_infix !== true){ - throw new CsvError$1('CSV_INVALID_OPTION_COMMENT', [ - 'Invalid option comment_no_infix:', - 'value must be a boolean,', - `got ${JSON.stringify(options.comment_no_infix)}` - ], options); + } else if (options.comment_no_infix !== true) { + throw new CsvError$1( + "CSV_INVALID_OPTION_COMMENT", + [ + "Invalid option comment_no_infix:", + "value must be a boolean,", + `got ${JSON.stringify(options.comment_no_infix)}`, + ], + options, + ); } // Normalize option `delimiter` const delimiter_json = JSON.stringify(options.delimiter); - if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter]; - if(options.delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); - } - options.delimiter = options.delimiter.map(function(delimiter){ - if(delimiter === undefined || delimiter === null || delimiter === false){ - return Buffer.from(',', options.encoding); - } - if(typeof delimiter === 'string'){ + if (!Array.isArray(options.delimiter)) + options.delimiter = [options.delimiter]; + if (options.delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); + } + options.delimiter = options.delimiter.map(function (delimiter) { + if (delimiter === undefined || delimiter === null || delimiter === false) { + return Buffer.from(",", options.encoding); + } + if (typeof delimiter === "string") { delimiter = Buffer.from(delimiter, options.encoding); } - if(!isBuffer$1(delimiter) || delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_DELIMITER', [ - 'Invalid option delimiter:', - 'delimiter must be a non empty string or buffer or array of string|buffer,', - `got ${delimiter_json}` - ], options); + if (!isBuffer$1(delimiter) || delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_DELIMITER", + [ + "Invalid option delimiter:", + "delimiter must be a non empty string or buffer or array of string|buffer,", + `got ${delimiter_json}`, + ], + options, + ); } return delimiter; }); // Normalize option `escape` - if(options.escape === undefined || options.escape === true){ + if (options.escape === undefined || options.escape === true) { options.escape = Buffer.from('"', options.encoding); - }else if(typeof options.escape === 'string'){ + } else if (typeof options.escape === "string") { options.escape = Buffer.from(options.escape, options.encoding); - }else if (options.escape === null || options.escape === false){ + } else if (options.escape === null || options.escape === false) { options.escape = null; } - if(options.escape !== null){ - if(!isBuffer$1(options.escape)){ - throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`); + if (options.escape !== null) { + if (!isBuffer$1(options.escape)) { + throw new Error( + `Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`, + ); } } // Normalize option `from` - if(options.from === undefined || options.from === null){ + if (options.from === undefined || options.from === null) { options.from = 1; - }else { - if(typeof options.from === 'string' && /\d+/.test(options.from)){ + } else { + if (typeof options.from === "string" && /\d+/.test(options.from)) { options.from = parseInt(options.from); } - if(Number.isInteger(options.from)){ - if(options.from < 0){ - throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`); + if (Number.isInteger(options.from)) { + if (options.from < 0) { + throw new Error( + `Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`, + ); } - }else { - throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`); + } else { + throw new Error( + `Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`, + ); } } // Normalize option `from_line` - if(options.from_line === undefined || options.from_line === null){ + if (options.from_line === undefined || options.from_line === null) { options.from_line = 1; - }else { - if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){ + } else { + if ( + typeof options.from_line === "string" && + /\d+/.test(options.from_line) + ) { options.from_line = parseInt(options.from_line); } - if(Number.isInteger(options.from_line)){ - if(options.from_line <= 0){ - throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`); + if (Number.isInteger(options.from_line)) { + if (options.from_line <= 0) { + throw new Error( + `Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`, + ); } - }else { - throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`); + } else { + throw new Error( + `Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`, + ); } } // Normalize options `ignore_last_delimiters` - if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){ + if ( + options.ignore_last_delimiters === undefined || + options.ignore_last_delimiters === null + ) { options.ignore_last_delimiters = false; - }else if(typeof options.ignore_last_delimiters === 'number'){ + } else if (typeof options.ignore_last_delimiters === "number") { options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters); - if(options.ignore_last_delimiters === 0){ + if (options.ignore_last_delimiters === 0) { options.ignore_last_delimiters = false; } - }else if(typeof options.ignore_last_delimiters !== 'boolean'){ - throw new CsvError$1('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [ - 'Invalid option `ignore_last_delimiters`:', - 'the value must be a boolean value or an integer,', - `got ${JSON.stringify(options.ignore_last_delimiters)}` - ], options); + } else if (typeof options.ignore_last_delimiters !== "boolean") { + throw new CsvError$1( + "CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS", + [ + "Invalid option `ignore_last_delimiters`:", + "the value must be a boolean value or an integer,", + `got ${JSON.stringify(options.ignore_last_delimiters)}`, + ], + options, + ); } - if(options.ignore_last_delimiters === true && options.columns === false){ - throw new CsvError$1('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [ - 'The option `ignore_last_delimiters`', - 'requires the activation of the `columns` option' - ], options); + if (options.ignore_last_delimiters === true && options.columns === false) { + throw new CsvError$1( + "CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS", + [ + "The option `ignore_last_delimiters`", + "requires the activation of the `columns` option", + ], + options, + ); } // Normalize option `info` - if(options.info === undefined || options.info === null || options.info === false){ + if ( + options.info === undefined || + options.info === null || + options.info === false + ) { options.info = false; - }else if(options.info !== true){ - throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`); + } else if (options.info !== true) { + throw new Error( + `Invalid Option: info must be true, got ${JSON.stringify(options.info)}`, + ); } // Normalize option `max_record_size` - if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){ + if ( + options.max_record_size === undefined || + options.max_record_size === null || + options.max_record_size === false + ) { options.max_record_size = 0; - }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){ + } else if ( + Number.isInteger(options.max_record_size) && + options.max_record_size >= 0 + ) ; else if ( + typeof options.max_record_size === "string" && + /\d+/.test(options.max_record_size) + ) { options.max_record_size = parseInt(options.max_record_size); - }else { - throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`); + } else { + throw new Error( + `Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`, + ); } // Normalize option `objname` - if(options.objname === undefined || options.objname === null || options.objname === false){ + if ( + options.objname === undefined || + options.objname === null || + options.objname === false + ) { options.objname = undefined; - }else if(isBuffer$1(options.objname)){ - if(options.objname.length === 0){ + } else if (isBuffer$1(options.objname)) { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty buffer`); } - if(options.encoding === null);else { + if (options.encoding === null) ; else { options.objname = options.objname.toString(options.encoding); } - }else if(typeof options.objname === 'string'){ - if(options.objname.length === 0){ + } else if (typeof options.objname === "string") { + if (options.objname.length === 0) { throw new Error(`Invalid Option: objname must be a non empty string`); } // Great, nothing to do - }else if(typeof options.objname === 'number');else { - throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`); + } else if (typeof options.objname === "number") ; else { + throw new Error( + `Invalid Option: objname must be a string or a buffer, got ${options.objname}`, + ); } - if(options.objname !== undefined){ - if(typeof options.objname === 'number'){ - if(options.columns !== false){ - throw Error('Invalid Option: objname index cannot be combined with columns or be defined as a field'); + if (options.objname !== undefined) { + if (typeof options.objname === "number") { + if (options.columns !== false) { + throw Error( + "Invalid Option: objname index cannot be combined with columns or be defined as a field", + ); } - }else { // A string or a buffer - if(options.columns === false){ - throw Error('Invalid Option: objname field must be combined with columns or be defined as an index'); + } else { + // A string or a buffer + if (options.columns === false) { + throw Error( + "Invalid Option: objname field must be combined with columns or be defined as an index", + ); } } } // Normalize option `on_record` - if(options.on_record === undefined || options.on_record === null){ + if (options.on_record === undefined || options.on_record === null) { options.on_record = undefined; - }else if(typeof options.on_record !== 'function'){ - throw new CsvError$1('CSV_INVALID_OPTION_ON_RECORD', [ - 'Invalid option `on_record`:', - 'expect a function,', - `got ${JSON.stringify(options.on_record)}` - ], options); + } else if (typeof options.on_record !== "function") { + throw new CsvError$1( + "CSV_INVALID_OPTION_ON_RECORD", + [ + "Invalid option `on_record`:", + "expect a function,", + `got ${JSON.stringify(options.on_record)}`, + ], + options, + ); } // Normalize option `on_skip` // options.on_skip ??= (err, chunk) => { // this.emit('skip', err, chunk); // }; - if(options.on_skip !== undefined && options.on_skip !== null && typeof options.on_skip !== 'function'){ - throw new Error(`Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`); + if ( + options.on_skip !== undefined && + options.on_skip !== null && + typeof options.on_skip !== "function" + ) { + throw new Error( + `Invalid Option: on_skip must be a function, got ${JSON.stringify(options.on_skip)}`, + ); } // Normalize option `quote` - if(options.quote === null || options.quote === false || options.quote === ''){ + if ( + options.quote === null || + options.quote === false || + options.quote === "" + ) { options.quote = null; - }else { - if(options.quote === undefined || options.quote === true){ + } else { + if (options.quote === undefined || options.quote === true) { options.quote = Buffer.from('"', options.encoding); - }else if(typeof options.quote === 'string'){ + } else if (typeof options.quote === "string") { options.quote = Buffer.from(options.quote, options.encoding); } - if(!isBuffer$1(options.quote)){ - throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`); + if (!isBuffer$1(options.quote)) { + throw new Error( + `Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`, + ); } } // Normalize option `raw` - if(options.raw === undefined || options.raw === null || options.raw === false){ + if ( + options.raw === undefined || + options.raw === null || + options.raw === false + ) { options.raw = false; - }else if(options.raw !== true){ - throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`); + } else if (options.raw !== true) { + throw new Error( + `Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`, + ); } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined){ + if (options.record_delimiter === undefined) { options.record_delimiter = []; - }else if(typeof options.record_delimiter === 'string' || isBuffer$1(options.record_delimiter)){ - if(options.record_delimiter.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); + } else if ( + typeof options.record_delimiter === "string" || + isBuffer$1(options.record_delimiter) + ) { + if (options.record_delimiter.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); } options.record_delimiter = [options.record_delimiter]; - }else if(!Array.isArray(options.record_delimiter)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer,', - `got ${JSON.stringify(options.record_delimiter)}` - ], options); - } - options.record_delimiter = options.record_delimiter.map(function(rd, i){ - if(typeof rd !== 'string' && ! isBuffer$1(rd)){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a string, a buffer or array of string|buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - }else if(rd.length === 0){ - throw new CsvError$1('CSV_INVALID_OPTION_RECORD_DELIMITER', [ - 'Invalid option `record_delimiter`:', - 'value must be a non empty string or buffer', - `at index ${i},`, - `got ${JSON.stringify(rd)}` - ], options); - } - if(typeof rd === 'string'){ + } else if (!Array.isArray(options.record_delimiter)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer,", + `got ${JSON.stringify(options.record_delimiter)}`, + ], + options, + ); + } + options.record_delimiter = options.record_delimiter.map(function (rd, i) { + if (typeof rd !== "string" && !isBuffer$1(rd)) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a string, a buffer or array of string|buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } else if (rd.length === 0) { + throw new CsvError$1( + "CSV_INVALID_OPTION_RECORD_DELIMITER", + [ + "Invalid option `record_delimiter`:", + "value must be a non empty string or buffer", + `at index ${i},`, + `got ${JSON.stringify(rd)}`, + ], + options, + ); + } + if (typeof rd === "string") { rd = Buffer.from(rd, options.encoding); } return rd; }); // Normalize option `relax_column_count` - if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){ + if (typeof options.relax_column_count === "boolean") ; else if ( + options.relax_column_count === undefined || + options.relax_column_count === null + ) { options.relax_column_count = false; - }else { - throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`, + ); } - if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){ + if (typeof options.relax_column_count_less === "boolean") ; else if ( + options.relax_column_count_less === undefined || + options.relax_column_count_less === null + ) { options.relax_column_count_less = false; - }else { - throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`, + ); } - if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){ + if (typeof options.relax_column_count_more === "boolean") ; else if ( + options.relax_column_count_more === undefined || + options.relax_column_count_more === null + ) { options.relax_column_count_more = false; - }else { - throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`); + } else { + throw new Error( + `Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`, + ); } // Normalize option `relax_quotes` - if(typeof options.relax_quotes === 'boolean');else if(options.relax_quotes === undefined || options.relax_quotes === null){ + if (typeof options.relax_quotes === "boolean") ; else if ( + options.relax_quotes === undefined || + options.relax_quotes === null + ) { options.relax_quotes = false; - }else { - throw new Error(`Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`); + } else { + throw new Error( + `Invalid Option: relax_quotes must be a boolean, got ${JSON.stringify(options.relax_quotes)}`, + ); } // Normalize option `skip_empty_lines` - if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){ + if (typeof options.skip_empty_lines === "boolean") ; else if ( + options.skip_empty_lines === undefined || + options.skip_empty_lines === null + ) { options.skip_empty_lines = false; - }else { - throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`); + } else { + throw new Error( + `Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`, + ); } // Normalize option `skip_records_with_empty_values` - if(typeof options.skip_records_with_empty_values === 'boolean');else if(options.skip_records_with_empty_values === undefined || options.skip_records_with_empty_values === null){ + if (typeof options.skip_records_with_empty_values === "boolean") ; else if ( + options.skip_records_with_empty_values === undefined || + options.skip_records_with_empty_values === null + ) { options.skip_records_with_empty_values = false; - }else { - throw new Error(`Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_records_with_empty_values)}`, + ); } // Normalize option `skip_records_with_error` - if(typeof options.skip_records_with_error === 'boolean');else if(options.skip_records_with_error === undefined || options.skip_records_with_error === null){ + if (typeof options.skip_records_with_error === "boolean") ; else if ( + options.skip_records_with_error === undefined || + options.skip_records_with_error === null + ) { options.skip_records_with_error = false; - }else { - throw new Error(`Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`); + } else { + throw new Error( + `Invalid Option: skip_records_with_error must be a boolean, got ${JSON.stringify(options.skip_records_with_error)}`, + ); } // Normalize option `rtrim` - if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){ + if ( + options.rtrim === undefined || + options.rtrim === null || + options.rtrim === false + ) { options.rtrim = false; - }else if(options.rtrim !== true){ - throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`); + } else if (options.rtrim !== true) { + throw new Error( + `Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`, + ); } // Normalize option `ltrim` - if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){ + if ( + options.ltrim === undefined || + options.ltrim === null || + options.ltrim === false + ) { options.ltrim = false; - }else if(options.ltrim !== true){ - throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`); + } else if (options.ltrim !== true) { + throw new Error( + `Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`, + ); } // Normalize option `trim` - if(options.trim === undefined || options.trim === null || options.trim === false){ + if ( + options.trim === undefined || + options.trim === null || + options.trim === false + ) { options.trim = false; - }else if(options.trim !== true){ - throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`); + } else if (options.trim !== true) { + throw new Error( + `Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`, + ); } // Normalize options `trim`, `ltrim` and `rtrim` - if(options.trim === true && opts.ltrim !== false){ + if (options.trim === true && opts.ltrim !== false) { options.ltrim = true; - }else if(options.ltrim !== true){ + } else if (options.ltrim !== true) { options.ltrim = false; } - if(options.trim === true && opts.rtrim !== false){ + if (options.trim === true && opts.rtrim !== false) { options.rtrim = true; - }else if(options.rtrim !== true){ + } else if (options.rtrim !== true) { options.rtrim = false; } // Normalize option `to` - if(options.to === undefined || options.to === null){ + if (options.to === undefined || options.to === null) { options.to = -1; - }else { - if(typeof options.to === 'string' && /\d+/.test(options.to)){ + } else { + if (typeof options.to === "string" && /\d+/.test(options.to)) { options.to = parseInt(options.to); } - if(Number.isInteger(options.to)){ - if(options.to <= 0){ - throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`); + if (Number.isInteger(options.to)) { + if (options.to <= 0) { + throw new Error( + `Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`, + ); } - }else { - throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`); + } else { + throw new Error( + `Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`, + ); } } // Normalize option `to_line` - if(options.to_line === undefined || options.to_line === null){ + if (options.to_line === undefined || options.to_line === null) { options.to_line = -1; - }else { - if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){ + } else { + if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) { options.to_line = parseInt(options.to_line); } - if(Number.isInteger(options.to_line)){ - if(options.to_line <= 0){ - throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`); + if (Number.isInteger(options.to_line)) { + if (options.to_line <= 0) { + throw new Error( + `Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`, + ); } - }else { - throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`); + } else { + throw new Error( + `Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`, + ); } } return options; }; - const isRecordEmpty = function(record){ - return record.every((field) => field == null || field.toString && field.toString().trim() === ''); + const isRecordEmpty = function (record) { + return record.every( + (field) => + field == null || (field.toString && field.toString().trim() === ""), + ); }; const cr = 13; // `\r`, carriage return, 0x0D in hexadécimal, 13 in decimal @@ -6072,21 +6351,21 @@ // Buffer.from("\ufeff") // Buffer.from([239, 187, 191]) // Buffer.from('EFBBBF', 'hex') - 'utf8': Buffer.from([239, 187, 191]), + utf8: Buffer.from([239, 187, 191]), // Note, the following are equals: // Buffer.from "\ufeff", 'utf16le // Buffer.from([255, 254]) - 'utf16le': Buffer.from([255, 254]) + utf16le: Buffer.from([255, 254]), }; - const transform$1 = function(original_options = {}) { + const transform$1 = function (original_options = {}) { const info = { bytes: 0, comment_lines: 0, empty_lines: 0, invalid_field_length: 0, lines: 1, - records: 0 + records: 0, }; const options = normalize_options$1(original_options); return { @@ -6094,10 +6373,11 @@ original_options: original_options, options: options, state: init_state(options), - __needMoreData: function(i, bufLen, end){ - if(end) return false; - const {encoding, escape, quote} = this.options; - const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state; + __needMoreData: function (i, bufLen, end) { + if (end) return false; + const { encoding, escape, quote } = this.options; + const { quoting, needMoreDataSize, recordDelimiterMaxLength } = + this.state; const numOfCharLeft = bufLen - i - 1; const requiredLength = Math.max( needMoreDataSize, @@ -6107,55 +6387,73 @@ // 2. We set the length to windows line ending in the current encoding // Note, that encoding is known from user or bom discovery at that point // recordDelimiterMaxLength, - recordDelimiterMaxLength === 0 ? Buffer.from('\r\n', encoding).length : recordDelimiterMaxLength, + recordDelimiterMaxLength === 0 + ? Buffer.from("\r\n", encoding).length + : recordDelimiterMaxLength, // Skip if remaining buffer can be an escaped quote - quoting ? ((escape === null ? 0 : escape.length) + quote.length) : 0, + quoting ? (escape === null ? 0 : escape.length) + quote.length : 0, // Skip if remaining buffer can be record delimiter following the closing quote - quoting ? (quote.length + recordDelimiterMaxLength) : 0, + quoting ? quote.length + recordDelimiterMaxLength : 0, ); return numOfCharLeft < requiredLength; }, // Central parser implementation - parse: function(nextBuf, end, push, close){ - const {bom, comment_no_infix, encoding, from_line, ltrim, max_record_size,raw, relax_quotes, rtrim, skip_empty_lines, to, to_line} = this.options; - let {comment, escape, quote, record_delimiter} = this.options; - const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state; + parse: function (nextBuf, end, push, close) { + const { + bom, + comment_no_infix, + encoding, + from_line, + ltrim, + max_record_size, + raw, + relax_quotes, + rtrim, + skip_empty_lines, + to, + to_line, + } = this.options; + let { comment, escape, quote, record_delimiter } = this.options; + const { bomSkipped, previousBuf, rawBuffer, escapeIsQuote } = this.state; let buf; - if(previousBuf === undefined){ - if(nextBuf === undefined){ + if (previousBuf === undefined) { + if (nextBuf === undefined) { // Handle empty string close(); return; - }else { + } else { buf = nextBuf; } - }else if(previousBuf !== undefined && nextBuf === undefined){ + } else if (previousBuf !== undefined && nextBuf === undefined) { buf = previousBuf; - }else { + } else { buf = Buffer.concat([previousBuf, nextBuf]); } // Handle UTF BOM - if(bomSkipped === false){ - if(bom === false){ + if (bomSkipped === false) { + if (bom === false) { this.state.bomSkipped = true; - }else if(buf.length < 3){ + } else if (buf.length < 3) { // No enough data - if(end === false){ + if (end === false) { // Wait for more data this.state.previousBuf = buf; return; } - }else { - for(const encoding in boms){ - if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){ + } else { + for (const encoding in boms) { + if (boms[encoding].compare(buf, 0, boms[encoding].length) === 0) { // Skip BOM const bomLength = boms[encoding].length; this.state.bufBytesStart += bomLength; buf = buf.slice(bomLength); // Renormalize original options with the new encoding - this.options = normalize_options$1({...this.original_options, encoding: encoding}); + this.options = normalize_options$1({ + ...this.original_options, + encoding: encoding, + }); // Options will re-evaluate the Buffer with the new encoding - ({comment, escape, quote } = this.options); + ({ comment, escape, quote } = this.options); break; } } @@ -6164,51 +6462,62 @@ } const bufLen = buf.length; let pos; - for(pos = 0; pos < bufLen; pos++){ + for (pos = 0; pos < bufLen; pos++) { // Ensure we get enough space to look ahead // There should be a way to move this out of the loop - if(this.__needMoreData(pos, bufLen, end)){ + if (this.__needMoreData(pos, bufLen, end)) { break; } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } - if(to_line !== -1 && this.info.lines > to_line){ + if (to_line !== -1 && this.info.lines > to_line) { this.state.stop = true; close(); return; } // Auto discovery of record_delimiter, unix, mac and windows supported - if(this.state.quoting === false && record_delimiter.length === 0){ - const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos); - if(record_delimiterCount){ + if (this.state.quoting === false && record_delimiter.length === 0) { + const record_delimiterCount = this.__autoDiscoverRecordDelimiter( + buf, + pos, + ); + if (record_delimiterCount) { record_delimiter = this.options.record_delimiter; } } const chr = buf[pos]; - if(raw === true){ + if (raw === true) { rawBuffer.append(chr); } - if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false){ + if ( + (chr === cr || chr === nl) && + this.state.wasRowDelimiter === false + ) { this.state.wasRowDelimiter = true; } // Previous char was a valid escape char // treat the current char as a regular char - if(this.state.escaping === true){ + if (this.state.escaping === true) { this.state.escaping = false; - }else { + } else { // Escape is only active inside quoted fields // We are quoting, the char is an escape chr and there is a chr to escape // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){ - if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){ - if(escapeIsQuote){ - if(this.__isQuote(buf, pos+escape.length)){ + if ( + escape !== null && + this.state.quoting === true && + this.__isEscape(buf, pos, chr) && + pos + escape.length < bufLen + ) { + if (escapeIsQuote) { + if (this.__isQuote(buf, pos + escape.length)) { this.state.escaping = true; pos += escape.length - 1; continue; } - }else { + } else { this.state.escaping = true; pos += escape.length - 1; continue; @@ -6216,74 +6525,122 @@ } // Not currently escaping and chr is a quote // TODO: need to compare bytes instead of single char - if(this.state.commenting === false && this.__isQuote(buf, pos)){ - if(this.state.quoting === true){ - const nextChr = buf[pos+quote.length]; - const isNextChrTrimable = rtrim && this.__isCharTrimable(buf, pos+quote.length); - const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr); - const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr); - const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length); + if (this.state.commenting === false && this.__isQuote(buf, pos)) { + if (this.state.quoting === true) { + const nextChr = buf[pos + quote.length]; + const isNextChrTrimable = + rtrim && this.__isCharTrimable(buf, pos + quote.length); + const isNextChrComment = + comment !== null && + this.__compareBytes(comment, buf, pos + quote.length, nextChr); + const isNextChrDelimiter = this.__isDelimiter( + buf, + pos + quote.length, + nextChr, + ); + const isNextChrRecordDelimiter = + record_delimiter.length === 0 + ? this.__autoDiscoverRecordDelimiter(buf, pos + quote.length) + : this.__isRecordDelimiter(nextChr, buf, pos + quote.length); // Escape a quote // Treat next char as a regular character - if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){ + if ( + escape !== null && + this.__isEscape(buf, pos, chr) && + this.__isQuote(buf, pos + escape.length) + ) { pos += escape.length - 1; - }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){ + } else if ( + !nextChr || + isNextChrDelimiter || + isNextChrRecordDelimiter || + isNextChrComment || + isNextChrTrimable + ) { this.state.quoting = false; this.state.wasQuoting = true; pos += quote.length - 1; continue; - }else if(relax_quotes === false){ + } else if (relax_quotes === false) { const err = this.__error( - new CsvError$1('CSV_INVALID_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - `got "${String.fromCharCode(nextChr)}"`, - `at line ${this.info.lines}`, - 'instead of delimiter, record delimiter, trimable character', - '(if activated) or comment', - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_INVALID_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + `got "${String.fromCharCode(nextChr)}"`, + `at line ${this.info.lines}`, + "instead of delimiter, record delimiter, trimable character", + "(if activated) or comment", + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { this.state.quoting = false; this.state.wasQuoting = true; this.state.field.prepend(quote); pos += quote.length - 1; } - }else { - if(this.state.field.length !== 0){ + } else { + if (this.state.field.length !== 0) { // In relax_quotes mode, treat opening quote preceded by chrs as regular - if(relax_quotes === false){ + if (relax_quotes === false) { const info = this.__infoField(); - const bom = Object.keys(boms).map(b => boms[b].equals(this.state.field.toString()) ? b : false).filter(Boolean)[0]; + const bom = Object.keys(boms) + .map((b) => + boms[b].equals(this.state.field.toString()) ? b : false, + ) + .filter(Boolean)[0]; const err = this.__error( - new CsvError$1('INVALID_OPENING_QUOTE', [ - 'Invalid Opening Quote:', - `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, - bom ? `(${bom} bom)` : undefined - ], this.options, info, { - field: this.state.field, - }) + new CsvError$1( + "INVALID_OPENING_QUOTE", + [ + "Invalid Opening Quote:", + `a quote is found on field ${JSON.stringify(info.column)} at line ${info.lines}, value is ${JSON.stringify(this.state.field.toString(encoding))}`, + bom ? `(${bom} bom)` : undefined, + ], + this.options, + info, + { + field: this.state.field, + }, + ), ); - if(err !== undefined) return err; + if (err !== undefined) return err; } - }else { + } else { this.state.quoting = true; pos += quote.length - 1; continue; } } } - if(this.state.quoting === false){ - const recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos); - if(recordDelimiterLength !== 0){ + if (this.state.quoting === false) { + const recordDelimiterLength = this.__isRecordDelimiter( + chr, + buf, + pos, + ); + if (recordDelimiterLength !== 0) { // Do not emit comments which take a full line - const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0); - if(skipCommentLine){ + const skipCommentLine = + this.state.commenting && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0; + if (skipCommentLine) { this.info.comment_lines++; // Skip full comment line - }else { + } else { // Activate records emition if above from_line - if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){ + if ( + this.state.enabled === false && + this.info.lines + + (this.state.wasRowDelimiter === true ? 1 : 0) >= + from_line + ) { this.state.enabled = true; this.__resetField(); this.__resetRecord(); @@ -6291,18 +6648,24 @@ continue; } // Skip if line is empty and skip_empty_lines activated - if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){ + if ( + skip_empty_lines === true && + this.state.wasQuoting === false && + this.state.record.length === 0 && + this.state.field.length === 0 + ) { this.info.empty_lines++; pos += recordDelimiterLength - 1; continue; } this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; - this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength; + if (errField !== undefined) return errField; + this.info.bytes = + this.state.bufBytesStart + pos + recordDelimiterLength; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - if(to !== -1 && this.info.records >= to){ + if (errRecord !== undefined) return errRecord; + if (to !== -1 && this.info.records >= to) { this.state.stop = true; close(); return; @@ -6312,157 +6675,218 @@ pos += recordDelimiterLength - 1; continue; } - if(this.state.commenting){ + if (this.state.commenting) { continue; } - if(comment !== null && (comment_no_infix === false || (this.state.record.length === 0 && this.state.field.length === 0))) { + if ( + comment !== null && + (comment_no_infix === false || + (this.state.record.length === 0 && + this.state.field.length === 0)) + ) { const commentCount = this.__compareBytes(comment, buf, pos, chr); - if(commentCount !== 0){ + if (commentCount !== 0) { this.state.commenting = true; continue; } } const delimiterLength = this.__isDelimiter(buf, pos, chr); - if(delimiterLength !== 0){ + if (delimiterLength !== 0) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; pos += delimiterLength - 1; continue; } } } - if(this.state.commenting === false){ - if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){ + if (this.state.commenting === false) { + if ( + max_record_size !== 0 && + this.state.record_length + this.state.field.length > max_record_size + ) { return this.__error( - new CsvError$1('CSV_MAX_RECORD_SIZE', [ - 'Max Record Size:', - 'record exceed the maximum number of tolerated bytes', - `of ${max_record_size}`, - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_MAX_RECORD_SIZE", + [ + "Max Record Size:", + "record exceed the maximum number of tolerated bytes", + `of ${max_record_size}`, + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); } } - const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(buf, pos); + const lappend = + ltrim === false || + this.state.quoting === true || + this.state.field.length !== 0 || + !this.__isCharTrimable(buf, pos); // rtrim in non quoting is handle in __onField const rappend = rtrim === false || this.state.wasQuoting === false; - if(lappend === true && rappend === true){ + if (lappend === true && rappend === true) { this.state.field.append(chr); - }else if(rtrim === true && !this.__isCharTrimable(buf, pos)){ + } else if (rtrim === true && !this.__isCharTrimable(buf, pos)) { return this.__error( - new CsvError$1('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [ - 'Invalid Closing Quote:', - 'found non trimable byte after quote', - `at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE", + [ + "Invalid Closing Quote:", + "found non trimable byte after quote", + `at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - }else { - if(lappend === false){ + } else { + if (lappend === false) { pos += this.__isCharTrimable(buf, pos) - 1; } continue; } } - if(end === true){ + if (end === true) { // Ensure we are not ending in a quoting state - if(this.state.quoting === true){ + if (this.state.quoting === true) { const err = this.__error( - new CsvError$1('CSV_QUOTE_NOT_CLOSED', [ - 'Quote Not Closed:', - `the parsing is finished with an opening quote at line ${this.info.lines}`, - ], this.options, this.__infoField()) + new CsvError$1( + "CSV_QUOTE_NOT_CLOSED", + [ + "Quote Not Closed:", + `the parsing is finished with an opening quote at line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + ), ); - if(err !== undefined) return err; - }else { + if (err !== undefined) return err; + } else { // Skip last line if it has no characters - if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){ + if ( + this.state.wasQuoting === true || + this.state.record.length !== 0 || + this.state.field.length !== 0 + ) { this.info.bytes = this.state.bufBytesStart + pos; const errField = this.__onField(); - if(errField !== undefined) return errField; + if (errField !== undefined) return errField; const errRecord = this.__onRecord(push); - if(errRecord !== undefined) return errRecord; - }else if(this.state.wasRowDelimiter === true){ + if (errRecord !== undefined) return errRecord; + } else if (this.state.wasRowDelimiter === true) { this.info.empty_lines++; - }else if(this.state.commenting === true){ + } else if (this.state.commenting === true) { this.info.comment_lines++; } } - }else { + } else { this.state.bufBytesStart += pos; this.state.previousBuf = buf.slice(pos); } - if(this.state.wasRowDelimiter === true){ + if (this.state.wasRowDelimiter === true) { this.info.lines++; this.state.wasRowDelimiter = false; } }, - __onRecord: function(push){ - 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; - const {enabled, record} = this.state; - if(enabled === false){ + __onRecord: function (push) { + 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; + const { enabled, record } = this.state; + if (enabled === false) { return this.__resetRecord(); } // Convert the first line into column names const recordLength = record.length; - if(columns === true){ - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (columns === true) { + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } return this.__firstLineToColumns(record); } - if(columns === false && this.info.records === 0){ + if (columns === false && this.info.records === 0) { this.state.expectedRecordLength = recordLength; } - if(recordLength !== this.state.expectedRecordLength){ - const err = columns === false ? - new CsvError$1('CSV_RECORD_INCONSISTENT_FIELDS_LENGTH', [ - 'Invalid Record Length:', - `expect ${this.state.expectedRecordLength},`, - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }) - : - new CsvError$1('CSV_RECORD_INCONSISTENT_COLUMNS', [ - 'Invalid Record Length:', - `columns length is ${columns.length},`, // rename columns - `got ${recordLength} on line ${this.info.lines}`, - ], this.options, this.__infoField(), { - record: record, - }); - if(relax_column_count === true || - (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) || - (relax_column_count_more === true && recordLength > this.state.expectedRecordLength)){ + if (recordLength !== this.state.expectedRecordLength) { + const err = + columns === false + ? new CsvError$1( + "CSV_RECORD_INCONSISTENT_FIELDS_LENGTH", + [ + "Invalid Record Length:", + `expect ${this.state.expectedRecordLength},`, + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ) + : new CsvError$1( + "CSV_RECORD_INCONSISTENT_COLUMNS", + [ + "Invalid Record Length:", + `columns length is ${columns.length},`, // rename columns + `got ${recordLength} on line ${this.info.lines}`, + ], + this.options, + this.__infoField(), + { + record: record, + }, + ); + if ( + relax_column_count === true || + (relax_column_count_less === true && + recordLength < this.state.expectedRecordLength) || + (relax_column_count_more === true && + recordLength > this.state.expectedRecordLength) + ) { this.info.invalid_field_length++; this.state.error = err; - // Error is undefined with skip_records_with_error - }else { + // Error is undefined with skip_records_with_error + } else { const finalErr = this.__error(err); - if(finalErr) return finalErr; + if (finalErr) return finalErr; } } - if(skip_records_with_empty_values === true && isRecordEmpty(record)){ + if (skip_records_with_empty_values === true && isRecordEmpty(record)) { this.__resetRecord(); return; } - if(this.state.recordHasError === true){ + if (this.state.recordHasError === true) { this.__resetRecord(); this.state.recordHasError = false; return; } this.info.records++; - if(from === 1 || this.info.records >= from){ - const {objname} = this.options; + if (from === 1 || this.info.records >= from) { + const { objname } = this.options; // With columns, records are object - if(columns !== false){ + if (columns !== false) { const obj = {}; // Transform record array to an object - for(let i = 0, l = record.length; i < l; i++){ - if(columns[i] === undefined || columns[i].disabled) continue; + for (let i = 0, l = record.length; i < l; i++) { + if (columns[i] === undefined || columns[i].disabled) continue; // Turn duplicate columns into an array - if (group_columns_by_name === true && obj[columns[i].name] !== undefined) { + if ( + group_columns_by_name === true && + obj[columns[i].name] !== undefined + ) { if (Array.isArray(obj[columns[i].name])) { obj[columns[i].name] = obj[columns[i].name].concat(record[i]); } else { @@ -6473,45 +6897,53 @@ } } // Without objname (default) - if(raw === true || info === true){ + if (raw === true || info === true) { const extRecord = Object.assign( - {record: obj}, - (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}), - (info === true ? {info: this.__infoRecord()}: {}) + { record: obj }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [obj[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [obj[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? obj : [obj[objname], obj] - , push); - if(err){ + objname === undefined ? obj : [obj[objname], obj], + push, + ); + if (err) { return err; } } - // Without columns, records are array - }else { - if(raw === true || info === true){ + // Without columns, records are array + } else { + if (raw === true || info === true) { const extRecord = Object.assign( - {record: record}, - raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}, - info === true ? {info: this.__infoRecord()}: {} + { record: record }, + raw === true + ? { raw: this.state.rawBuffer.toString(encoding) } + : {}, + info === true ? { info: this.__infoRecord() } : {}, ); const err = this.__push( - objname === undefined ? extRecord : [record[objname], extRecord] - , push); - if(err){ + objname === undefined ? extRecord : [record[objname], extRecord], + push, + ); + if (err) { return err; } - }else { + } else { const err = this.__push( - objname === undefined ? record : [record[objname], record] - , push); - if(err){ + objname === undefined ? record : [record[objname], record], + push, + ); + if (err) { return err; } } @@ -6519,19 +6951,28 @@ } this.__resetRecord(); }, - __firstLineToColumns: function(record){ - const {firstLineToHeaders} = this.state; - try{ - const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record); - if(!Array.isArray(headers)){ + __firstLineToColumns: function (record) { + const { firstLineToHeaders } = this.state; + try { + const headers = + firstLineToHeaders === undefined + ? record + : firstLineToHeaders.call(null, record); + if (!Array.isArray(headers)) { return this.__error( - new CsvError$1('CSV_INVALID_COLUMN_MAPPING', [ - 'Invalid Column Mapping:', - 'expect an array from column function,', - `got ${JSON.stringify(headers)}` - ], this.options, this.__infoField(), { - headers: headers, - }) + new CsvError$1( + "CSV_INVALID_COLUMN_MAPPING", + [ + "Invalid Column Mapping:", + "expect an array from column function,", + `got ${JSON.stringify(headers)}`, + ], + this.options, + this.__infoField(), + { + headers: headers, + }, + ), ); } const normalizedHeaders = normalize_columns_array(headers); @@ -6539,92 +6980,98 @@ this.options.columns = normalizedHeaders; this.__resetRecord(); return; - }catch(err){ + } catch (err) { return err; } }, - __resetRecord: function(){ - if(this.options.raw === true){ + __resetRecord: function () { + if (this.options.raw === true) { this.state.rawBuffer.reset(); } this.state.error = undefined; this.state.record = []; this.state.record_length = 0; }, - __onField: function(){ - const {cast, encoding, rtrim, max_record_size} = this.options; - const {enabled, wasQuoting} = this.state; + __onField: function () { + const { cast, encoding, rtrim, max_record_size } = this.options; + const { enabled, wasQuoting } = this.state; // Short circuit for the from_line options - if(enabled === false){ + if (enabled === false) { return this.__resetField(); } let field = this.state.field.toString(encoding); - if(rtrim === true && wasQuoting === false){ + if (rtrim === true && wasQuoting === false) { field = field.trimRight(); } - if(cast === true){ + if (cast === true) { const [err, f] = this.__cast(field); - if(err !== undefined) return err; + if (err !== undefined) return err; field = f; } this.state.record.push(field); // Increment record length if record size must not exceed a limit - if(max_record_size !== 0 && typeof field === 'string'){ + if (max_record_size !== 0 && typeof field === "string") { this.state.record_length += field.length; } this.__resetField(); }, - __resetField: function(){ + __resetField: function () { this.state.field.reset(); this.state.wasQuoting = false; }, - __push: function(record, push){ - const {on_record} = this.options; - if(on_record !== undefined){ + __push: function (record, push) { + const { on_record } = this.options; + if (on_record !== undefined) { const info = this.__infoRecord(); - try{ + try { record = on_record.call(null, record, info); - }catch(err){ + } catch (err) { return err; } - if(record === undefined || record === null){ return; } + if (record === undefined || record === null) { + return; + } } push(record); }, // Return a tuple with the error and the casted value - __cast: function(field){ - const {columns, relax_column_count} = this.options; + __cast: function (field) { + const { columns, relax_column_count } = this.options; const isColumns = Array.isArray(columns); // Dont loose time calling cast // because the final record is an object // and this field can't be associated to a key present in columns - if(isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length){ + if ( + isColumns === true && + relax_column_count && + this.options.columns.length <= this.state.record.length + ) { return [undefined, undefined]; } - if(this.state.castField !== null){ - try{ + if (this.state.castField !== null) { + try { const info = this.__infoField(); return [undefined, this.state.castField.call(null, field, info)]; - }catch(err){ + } catch (err) { return [err]; } } - if(this.__isFloat(field)){ + if (this.__isFloat(field)) { return [undefined, parseFloat(field)]; - }else if(this.options.cast_date !== false){ + } else if (this.options.cast_date !== false) { const info = this.__infoField(); return [undefined, this.options.cast_date.call(null, field, info)]; } return [undefined, field]; }, // Helper to test if a character is a space or a line delimiter - __isCharTrimable: function(buf, pos){ + __isCharTrimable: function (buf, pos) { const isTrim = (buf, pos) => { - const {timchars} = this.state; - loop1: for(let i = 0; i < timchars.length; i++){ + const { timchars } = this.state; + loop1: for (let i = 0; i < timchars.length; i++) { const timchar = timchars[i]; - for(let j = 0; j < timchar.length; j++){ - if(timchar[j] !== buf[pos+j]) continue loop1; + for (let j = 0; j < timchar.length; j++) { + if (timchar[j] !== buf[pos + j]) continue loop1; } return timchar.length; } @@ -6638,46 +7085,53 @@ // // return !isNaN( parseInt( obj ) ); // return /^(\-|\+)?[1-9][0-9]*$/.test(value) // } - __isFloat: function(value){ - return (value - parseFloat(value) + 1) >= 0; // Borrowed from jquery + __isFloat: function (value) { + return value - parseFloat(value) + 1 >= 0; // Borrowed from jquery }, - __compareBytes: function(sourceBuf, targetBuf, targetPos, firstByte){ - if(sourceBuf[0] !== firstByte) return 0; + __compareBytes: function (sourceBuf, targetBuf, targetPos, firstByte) { + if (sourceBuf[0] !== firstByte) return 0; const sourceLength = sourceBuf.length; - for(let i = 1; i < sourceLength; i++){ - if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0; + for (let i = 1; i < sourceLength; i++) { + if (sourceBuf[i] !== targetBuf[targetPos + i]) return 0; } return sourceLength; }, - __isDelimiter: function(buf, pos, chr){ - const {delimiter, ignore_last_delimiters} = this.options; - if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){ + __isDelimiter: function (buf, pos, chr) { + const { delimiter, ignore_last_delimiters } = this.options; + if ( + ignore_last_delimiters === true && + this.state.record.length === this.options.columns.length - 1 + ) { return 0; - }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){ + } else if ( + ignore_last_delimiters !== false && + typeof ignore_last_delimiters === "number" && + this.state.record.length === ignore_last_delimiters - 1 + ) { return 0; } - loop1: for(let i = 0; i < delimiter.length; i++){ + loop1: for (let i = 0; i < delimiter.length; i++) { const del = delimiter[i]; - if(del[0] === chr){ - for(let j = 1; j < del.length; j++){ - if(del[j] !== buf[pos+j]) continue loop1; + if (del[0] === chr) { + for (let j = 1; j < del.length; j++) { + if (del[j] !== buf[pos + j]) continue loop1; } return del.length; } } return 0; }, - __isRecordDelimiter: function(chr, buf, pos){ - const {record_delimiter} = this.options; + __isRecordDelimiter: function (chr, buf, pos) { + const { record_delimiter } = this.options; const recordDelimiterLength = record_delimiter.length; - loop1: for(let i = 0; i < recordDelimiterLength; i++){ + loop1: for (let i = 0; i < recordDelimiterLength; i++) { const rd = record_delimiter[i]; const rdLength = rd.length; - if(rd[0] !== chr){ + if (rd[0] !== chr) { continue; } - for(let j = 1; j < rdLength; j++){ - if(rd[j] !== buf[pos+j]){ + for (let j = 1; j < rdLength; j++) { + if (rd[j] !== buf[pos + j]) { continue loop1; } } @@ -6685,13 +7139,13 @@ } return 0; }, - __isEscape: function(buf, pos, chr){ - const {escape} = this.options; - if(escape === null) return false; + __isEscape: function (buf, pos, chr) { + const { escape } = this.options; + if (escape === null) return false; const l = escape.length; - if(escape[0] === chr){ - for(let i = 0; i < l; i++){ - if(escape[i] !== buf[pos+i]){ + if (escape[0] === chr) { + for (let i = 0; i < l; i++) { + if (escape[i] !== buf[pos + i]) { return false; } } @@ -6699,32 +7153,32 @@ } return false; }, - __isQuote: function(buf, pos){ - const {quote} = this.options; - if(quote === null) return false; + __isQuote: function (buf, pos) { + const { quote } = this.options; + if (quote === null) return false; const l = quote.length; - for(let i = 0; i < l; i++){ - if(quote[i] !== buf[pos+i]){ + for (let i = 0; i < l; i++) { + if (quote[i] !== buf[pos + i]) { return false; } } return true; }, - __autoDiscoverRecordDelimiter: function(buf, pos){ + __autoDiscoverRecordDelimiter: function (buf, pos) { const { encoding } = this.options; // Note, we don't need to cache this information in state, // It is only called on the first line until we find out a suitable // record delimiter. const rds = [ // Important, the windows line ending must be before mac os 9 - Buffer.from('\r\n', encoding), - Buffer.from('\n', encoding), - Buffer.from('\r', encoding), + Buffer.from("\r\n", encoding), + Buffer.from("\n", encoding), + Buffer.from("\r", encoding), ]; - loop: for(let i = 0; i < rds.length; i++){ + loop: for (let i = 0; i < rds.length; i++) { const l = rds[i].length; - for(let j = 0; j < l; j++){ - if(rds[i][j] !== buf[pos + j]){ + for (let j = 0; j < l; j++) { + if (rds[i][j] !== buf[pos + j]) { continue loop; } } @@ -6734,189 +7188,214 @@ } return 0; }, - __error: function(msg){ - const {encoding, raw, skip_records_with_error} = this.options; - const err = typeof msg === 'string' ? new Error(msg) : msg; - if(skip_records_with_error){ + __error: function (msg) { + const { encoding, raw, skip_records_with_error } = this.options; + const err = typeof msg === "string" ? new Error(msg) : msg; + if (skip_records_with_error) { this.state.recordHasError = true; - if(this.options.on_skip !== undefined){ - this.options.on_skip(err, raw ? this.state.rawBuffer.toString(encoding) : undefined); + if (this.options.on_skip !== undefined) { + this.options.on_skip( + err, + raw ? this.state.rawBuffer.toString(encoding) : undefined, + ); } // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined); return undefined; - }else { + } else { return err; } }, - __infoDataSet: function(){ + __infoDataSet: function () { return { ...this.info, - columns: this.options.columns + columns: this.options.columns, }; }, - __infoRecord: function(){ - const {columns, raw, encoding} = this.options; + __infoRecord: function () { + const { columns, raw, encoding } = this.options; return { ...this.__infoDataSet(), error: this.state.error, header: columns === true, index: this.state.record.length, - raw: raw ? this.state.rawBuffer.toString(encoding) : undefined + raw: raw ? this.state.rawBuffer.toString(encoding) : undefined, }; }, - __infoField: function(){ - const {columns} = this.options; + __infoField: function () { + const { columns } = this.options; const isColumns = Array.isArray(columns); return { ...this.__infoRecord(), - column: isColumns === true ? - (columns.length > this.state.record.length ? - columns[this.state.record.length].name : - null - ) : - this.state.record.length, + column: + isColumns === true + ? columns.length > this.state.record.length + ? columns[this.state.record.length].name + : null + : this.state.record.length, quoting: this.state.wasQuoting, }; - } + }, }; }; - const parse = function(data, opts={}){ - if(typeof data === 'string'){ + const parse = function (data, opts = {}) { + if (typeof data === "string") { data = Buffer.from(data); } const records = opts && opts.objname ? {} : []; const parser = transform$1(opts); const push = (record) => { - if(parser.options.objname === undefined) - records.push(record); + if (parser.options.objname === undefined) records.push(record); else { records[record[0]] = record[1]; } }; const close = () => {}; const err1 = parser.parse(data, false, push, close); - if(err1 !== undefined) throw err1; + if (err1 !== undefined) throw err1; const err2 = parser.parse(undefined, true, push, close); - if(err2 !== undefined) throw err2; + if (err2 !== undefined) throw err2; return records; }; // Lodash implementation of `get` - const charCodeOfDot = '.'.charCodeAt(0); + const charCodeOfDot = ".".charCodeAt(0); const reEscapeChar = /\\(\\)?/g; const rePropName = RegExp( // Match anything that isn't a dot or bracket. - '[^.[\\]]+' + '|' + - // Or match property names within brackets. - '\\[(?:' + + "[^.[\\]]+" + + "|" + + // Or match property names within brackets. + "\\[(?:" + // Match a non-string expression. - '([^"\'][^[]*)' + '|' + + "([^\"'][^[]*)" + + "|" + // Or match strings (supports escaping characters). - '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + - ')\\]'+ '|' + - // Or match "" as the space between consecutive dots or empty brackets. - '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' - , 'g'); + "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + + ")\\]" + + "|" + + // Or match "" as the space between consecutive dots or empty brackets. + "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", + "g", + ); const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; - const getTag = function(value){ + const getTag = function (value) { return Object.prototype.toString.call(value); }; - const isSymbol = function(value){ + const isSymbol = function (value) { const type = typeof value; - return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]'); + return ( + type === "symbol" || + (type === "object" && value && getTag(value) === "[object Symbol]") + ); }; - const isKey = function(value, object){ - if(Array.isArray(value)){ + const isKey = function (value, object) { + if (Array.isArray(value)) { return false; } const type = typeof value; - if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){ + if ( + type === "number" || + type === "symbol" || + type === "boolean" || + !value || + isSymbol(value) + ) { return true; } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); + return ( + reIsPlainProp.test(value) || + !reIsDeepProp.test(value) || + (object != null && value in Object(object)) + ); }; - const stringToPath = function(string){ + const stringToPath = function (string) { const result = []; - if(string.charCodeAt(0) === charCodeOfDot){ - result.push(''); + if (string.charCodeAt(0) === charCodeOfDot) { + result.push(""); } - string.replace(rePropName, function(match, expression, quote, subString){ + string.replace(rePropName, function (match, expression, quote, subString) { let key = match; - if(quote){ - key = subString.replace(reEscapeChar, '$1'); - }else if(expression){ + if (quote) { + key = subString.replace(reEscapeChar, "$1"); + } else if (expression) { key = expression.trim(); } result.push(key); }); return result; }; - const castPath = function(value, object){ - if(Array.isArray(value)){ + const castPath = function (value, object) { + if (Array.isArray(value)) { return value; } else { return isKey(value, object) ? [value] : stringToPath(value); } }; - const toKey = function(value){ - if(typeof value === 'string' || isSymbol(value)) - return value; + const toKey = function (value) { + if (typeof value === "string" || isSymbol(value)) return value; const result = `${value}`; // eslint-disable-next-line return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }; - const get = function(object, path){ + const get = function (object, path) { path = castPath(path, object); let index = 0; const length = path.length; - while(object != null && index < length){ + while (object != null && index < length) { object = object[toKey(path[index++])]; } - return (index && index === length) ? object : undefined; + return index && index === length ? object : undefined; }; - const is_object = function(obj){ - return typeof obj === 'object' && obj !== null && ! Array.isArray(obj); + const is_object = function (obj) { + return typeof obj === "object" && obj !== null && !Array.isArray(obj); }; - const normalize_columns = function(columns){ - if(columns === undefined || columns === null){ + const normalize_columns = function (columns) { + if (columns === undefined || columns === null) { return [undefined, undefined]; } - if(typeof columns !== 'object'){ + if (typeof columns !== "object") { return [Error('Invalid option "columns": expect an array or an object')]; } - if(!Array.isArray(columns)){ + if (!Array.isArray(columns)) { const newcolumns = []; - for(const k in columns){ + for (const k in columns) { newcolumns.push({ key: k, - header: columns[k] + header: columns[k], }); } columns = newcolumns; - }else { + } else { const newcolumns = []; - for(const column of columns){ - if(typeof column === 'string'){ + for (const column of columns) { + if (typeof column === "string") { newcolumns.push({ key: column, - header: column + header: column, }); - }else if(typeof column === 'object' && column !== null && !Array.isArray(column)){ - if(!column.key){ - return [Error('Invalid column definition: property "key" is required')]; + } else if ( + typeof column === "object" && + column !== null && + !Array.isArray(column) + ) { + if (!column.key) { + return [ + Error('Invalid column definition: property "key" is required'), + ]; } - if(column.header === undefined){ + if (column.header === undefined) { column.header = column.key; } newcolumns.push(column); - }else { - return [Error('Invalid column definition: expect a string or an object')]; + } else { + return [ + Error("Invalid column definition: expect a string or an object"), + ]; } } columns = newcolumns; @@ -6926,253 +7405,307 @@ class CsvError extends Error { constructor(code, message, ...contexts) { - if(Array.isArray(message)) message = message.join(' '); + if (Array.isArray(message)) message = message.join(" "); super(message); - if(Error.captureStackTrace !== undefined){ + if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, CsvError); } this.code = code; - for(const context of contexts){ - for(const key in context){ + for (const context of contexts) { + for (const key in context) { const value = context[key]; - this[key] = isBuffer$1(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value)); + this[key] = isBuffer$1(value) + ? value.toString() + : value == null + ? value + : JSON.parse(JSON.stringify(value)); } } } } - const underscore = function(str){ - return str.replace(/([A-Z])/g, function(_, match){ - return '_' + match.toLowerCase(); + const underscore = function (str) { + return str.replace(/([A-Z])/g, function (_, match) { + return "_" + match.toLowerCase(); }); }; - const normalize_options = function(opts) { + const normalize_options = function (opts) { const options = {}; // Merge with user options - for(const opt in opts){ + for (const opt in opts) { options[underscore(opt)] = opts[opt]; } // Normalize option `bom` - if(options.bom === undefined || options.bom === null || options.bom === false){ + if ( + options.bom === undefined || + options.bom === null || + options.bom === false + ) { options.bom = false; - }else if(options.bom !== true){ - return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [ - 'option `bom` is optional and must be a boolean value,', - `got ${JSON.stringify(options.bom)}` - ])]; + } else if (options.bom !== true) { + return [ + new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [ + "option `bom` is optional and must be a boolean value,", + `got ${JSON.stringify(options.bom)}`, + ]), + ]; } // Normalize option `delimiter` - if(options.delimiter === undefined || options.delimiter === null){ - options.delimiter = ','; - }else if(isBuffer$1(options.delimiter)){ + if (options.delimiter === undefined || options.delimiter === null) { + options.delimiter = ","; + } else if (isBuffer$1(options.delimiter)) { options.delimiter = options.delimiter.toString(); - }else if(typeof options.delimiter !== 'string'){ - return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [ - 'option `delimiter` must be a buffer or a string,', - `got ${JSON.stringify(options.delimiter)}` - ])]; + } else if (typeof options.delimiter !== "string") { + return [ + new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [ + "option `delimiter` must be a buffer or a string,", + `got ${JSON.stringify(options.delimiter)}`, + ]), + ]; } // Normalize option `quote` - if(options.quote === undefined || options.quote === null){ + if (options.quote === undefined || options.quote === null) { options.quote = '"'; - }else if(options.quote === true){ + } else if (options.quote === true) { options.quote = '"'; - }else if(options.quote === false){ - options.quote = ''; - }else if (isBuffer$1(options.quote)){ + } else if (options.quote === false) { + options.quote = ""; + } else if (isBuffer$1(options.quote)) { options.quote = options.quote.toString(); - }else if(typeof options.quote !== 'string'){ - return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [ - 'option `quote` must be a boolean, a buffer or a string,', - `got ${JSON.stringify(options.quote)}` - ])]; + } else if (typeof options.quote !== "string") { + return [ + new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [ + "option `quote` must be a boolean, a buffer or a string,", + `got ${JSON.stringify(options.quote)}`, + ]), + ]; } // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `escape_formulas` - if(options.escape_formulas === undefined || options.escape_formulas === null){ + if ( + options.escape_formulas === undefined || + options.escape_formulas === null + ) { options.escape_formulas = false; - }else if(typeof options.escape_formulas !== 'boolean'){ - return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [ - 'option `escape_formulas` must be a boolean,', - `got ${JSON.stringify(options.escape_formulas)}` - ])]; + } else if (typeof options.escape_formulas !== "boolean") { + return [ + new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [ + "option `escape_formulas` must be a boolean,", + `got ${JSON.stringify(options.escape_formulas)}`, + ]), + ]; } // Normalize option `quoted_empty` - if(options.quoted_empty === undefined || options.quoted_empty === null){ + if (options.quoted_empty === undefined || options.quoted_empty === null) { options.quoted_empty = undefined; } // Normalize option `quoted_match` - if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){ + if ( + options.quoted_match === undefined || + options.quoted_match === null || + options.quoted_match === false + ) { options.quoted_match = null; - }else if(!Array.isArray(options.quoted_match)){ + } else if (!Array.isArray(options.quoted_match)) { options.quoted_match = [options.quoted_match]; } - if(options.quoted_match){ - for(const quoted_match of options.quoted_match){ - const isString = typeof quoted_match === 'string'; + if (options.quoted_match) { + for (const quoted_match of options.quoted_match) { + const isString = typeof quoted_match === "string"; const isRegExp = quoted_match instanceof RegExp; - if(!isString && !isRegExp){ - return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)]; + if (!isString && !isRegExp) { + return [ + Error( + `Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`, + ), + ]; } } } // Normalize option `quoted_string` - if(options.quoted_string === undefined || options.quoted_string === null){ + if (options.quoted_string === undefined || options.quoted_string === null) { options.quoted_string = false; } // Normalize option `eof` - if(options.eof === undefined || options.eof === null){ + if (options.eof === undefined || options.eof === null) { options.eof = true; } // Normalize option `escape` - if(options.escape === undefined || options.escape === null){ + if (options.escape === undefined || options.escape === null) { options.escape = '"'; - }else if(isBuffer$1(options.escape)){ + } else if (isBuffer$1(options.escape)) { options.escape = options.escape.toString(); - }else if(typeof options.escape !== 'string'){ - return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)]; - } - if (options.escape.length > 1){ - return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)]; + } else if (typeof options.escape !== "string") { + return [ + Error( + `Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`, + ), + ]; + } + if (options.escape.length > 1) { + return [ + Error( + `Invalid Option: escape must be one character, got ${options.escape.length} characters`, + ), + ]; } // Normalize option `header` - if(options.header === undefined || options.header === null){ + if (options.header === undefined || options.header === null) { options.header = false; } // Normalize option `columns` const [errColumns, columns] = normalize_columns(options.columns); - if(errColumns !== undefined) return [errColumns]; + if (errColumns !== undefined) return [errColumns]; options.columns = columns; // Normalize option `quoted` - if(options.quoted === undefined || options.quoted === null){ + if (options.quoted === undefined || options.quoted === null) { options.quoted = false; } // Normalize option `cast` - if(options.cast === undefined || options.cast === null){ + if (options.cast === undefined || options.cast === null) { options.cast = {}; } // Normalize option cast.bigint - if(options.cast.bigint === undefined || options.cast.bigint === null){ + if (options.cast.bigint === undefined || options.cast.bigint === null) { // Cast boolean to string by default - options.cast.bigint = value => '' + value; + options.cast.bigint = (value) => "" + value; } // Normalize option cast.boolean - if(options.cast.boolean === undefined || options.cast.boolean === null){ + if (options.cast.boolean === undefined || options.cast.boolean === null) { // Cast boolean to string by default - options.cast.boolean = value => value ? '1' : ''; + options.cast.boolean = (value) => (value ? "1" : ""); } // Normalize option cast.date - if(options.cast.date === undefined || options.cast.date === null){ + if (options.cast.date === undefined || options.cast.date === null) { // Cast date to timestamp string by default - options.cast.date = value => '' + value.getTime(); + options.cast.date = (value) => "" + value.getTime(); } // Normalize option cast.number - if(options.cast.number === undefined || options.cast.number === null){ + if (options.cast.number === undefined || options.cast.number === null) { // Cast number to string using native casting by default - options.cast.number = value => '' + value; + options.cast.number = (value) => "" + value; } // Normalize option cast.object - if(options.cast.object === undefined || options.cast.object === null){ + if (options.cast.object === undefined || options.cast.object === null) { // Stringify object as JSON by default - options.cast.object = value => JSON.stringify(value); + options.cast.object = (value) => JSON.stringify(value); } // Normalize option cast.string - if(options.cast.string === undefined || options.cast.string === null){ + if (options.cast.string === undefined || options.cast.string === null) { // Leave string untouched - options.cast.string = function(value){return value;}; + options.cast.string = function (value) { + return value; + }; } // Normalize option `on_record` - if(options.on_record !== undefined && typeof options.on_record !== 'function'){ + if ( + options.on_record !== undefined && + typeof options.on_record !== "function" + ) { return [Error(`Invalid Option: "on_record" must be a function.`)]; } // Normalize option `record_delimiter` - if(options.record_delimiter === undefined || options.record_delimiter === null){ - options.record_delimiter = '\n'; - }else if(isBuffer$1(options.record_delimiter)){ - options.record_delimiter = options.record_delimiter.toString(); - }else if(typeof options.record_delimiter !== 'string'){ - return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)]; - } - switch(options.record_delimiter){ - case 'unix': + if ( + options.record_delimiter === undefined || + options.record_delimiter === null + ) { options.record_delimiter = "\n"; - break; - case 'mac': - options.record_delimiter = "\r"; - break; - case 'windows': - options.record_delimiter = "\r\n"; - break; - case 'ascii': - options.record_delimiter = "\u001e"; - break; - case 'unicode': - options.record_delimiter = "\u2028"; - break; + } else if (isBuffer$1(options.record_delimiter)) { + options.record_delimiter = options.record_delimiter.toString(); + } else if (typeof options.record_delimiter !== "string") { + return [ + Error( + `Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`, + ), + ]; + } + switch (options.record_delimiter) { + case "unix": + options.record_delimiter = "\n"; + break; + case "mac": + options.record_delimiter = "\r"; + break; + case "windows": + options.record_delimiter = "\r\n"; + break; + case "ascii": + options.record_delimiter = "\u001e"; + break; + case "unicode": + options.record_delimiter = "\u2028"; + break; } return [undefined, options]; }; const bom_utf8 = Buffer.from([239, 187, 191]); - const stringifier = function(options, state, info){ + const stringifier = function (options, state, info) { return { options: options, state: state, info: info, - __transform: function(chunk, push){ + __transform: function (chunk, push) { // Chunk validation - if(!Array.isArray(chunk) && typeof chunk !== 'object'){ - return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`); + if (!Array.isArray(chunk) && typeof chunk !== "object") { + return Error( + `Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`, + ); } // Detect columns from the first record - if(this.info.records === 0){ - if(Array.isArray(chunk)){ - if(this.options.header === true && this.options.columns === undefined){ - return Error('Undiscoverable Columns: header option requires column option or object records'); + if (this.info.records === 0) { + if (Array.isArray(chunk)) { + if ( + this.options.header === true && + this.options.columns === undefined + ) { + return Error( + "Undiscoverable Columns: header option requires column option or object records", + ); } - }else if(this.options.columns === undefined){ + } else if (this.options.columns === undefined) { const [err, columns] = normalize_columns(Object.keys(chunk)); - if(err) return; + if (err) return; this.options.columns = columns; } } // Emit the header - if(this.info.records === 0){ + if (this.info.records === 0) { this.bom(push); const err = this.headers(push); - if(err) return err; + if (err) return err; } // Emit and stringify the record if an object or an array - try{ + try { // this.emit('record', chunk, this.info.records); - if(this.options.on_record){ + if (this.options.on_record) { this.options.on_record(chunk, this.info.records); } - }catch(err){ + } catch (err) { return err; } // Convert the record into a string let err, chunk_string; - if(this.options.eof){ + if (this.options.eof) { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { + } else { chunk_string = chunk_string + this.options.record_delimiter; } - }else { + } else { [err, chunk_string] = this.stringify(chunk); - if(err) return err; - if(chunk_string === undefined){ + if (err) return err; + if (chunk_string === undefined) { return; - }else { - if(this.options.header || this.info.records){ + } else { + if (this.options.header || this.info.records) { chunk_string = this.options.record_delimiter + chunk_string; } } @@ -7181,96 +7714,136 @@ this.info.records++; push(chunk_string); }, - stringify: function(chunk, chunkIsHeader=false){ - if(typeof chunk !== 'object'){ + stringify: function (chunk, chunkIsHeader = false) { + if (typeof chunk !== "object") { return [undefined, chunk]; } - const {columns} = this.options; + const { columns } = this.options; const record = []; // Record is an array - if(Array.isArray(chunk)){ + if (Array.isArray(chunk)) { // We are getting an array but the user has specified output columns. In // this case, we respect the columns indexes - if(columns){ + if (columns) { chunk.splice(columns.length); } // Cast record elements - for(let i=0; i { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const { + delimiter, + escape, + quote, + quoted, + quoted_empty, + quoted_string, + quoted_match, + record_delimiter, + escape_formulas, + } = options; + if ("" === value && "" === field) { + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; - const shouldQuote = quotedMatch || true === quoted_empty || + const shouldQuote = + quotedMatch || + true === quoted_empty || (true === quoted_string && false !== quoted_empty); - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(value){ - if(typeof value !== 'string'){ - return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)]; + } else if (value) { + if (typeof value !== "string") { + return [ + Error( + `Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`, + ), + ]; } - const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0; - const containsQuote = (quote !== '') && value.indexOf(quote) >= 0; - const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote); + const containsdelimiter = + delimiter.length && value.indexOf(delimiter) >= 0; + const containsQuote = quote !== "" && value.indexOf(quote) >= 0; + const containsEscape = value.indexOf(escape) >= 0 && escape !== quote; const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0; - const quotedString = quoted_string && typeof field === 'string'; - let quotedMatch = quoted_match && quoted_match.filter(quoted_match => { - if(typeof quoted_match === 'string'){ - return value.indexOf(quoted_match) !== -1; - }else { - return quoted_match.test(value); - } - }); + const quotedString = quoted_string && typeof field === "string"; + let quotedMatch = + quoted_match && + quoted_match.filter((quoted_match) => { + if (typeof quoted_match === "string") { + return value.indexOf(quoted_match) !== -1; + } else { + return quoted_match.test(value); + } + }); quotedMatch = quotedMatch && quotedMatch.length > 0; // See https://github.com/adaltas/node-csv/pull/387 // More about CSV injection or formula injection, when websites embed @@ -7280,133 +7853,152 @@ // Apple Numbers unicode normalization is empirical from testing if (escape_formulas) { switch (value[0]) { - case '=': - case '+': - case '-': - case '@': - case '\t': - case '\r': - case '\uFF1D': // Unicode '=' - case '\uFF0B': // Unicode '+' - case '\uFF0D': // Unicode '-' - case '\uFF20': // Unicode '@' - value = `'${value}`; - break; + case "=": + case "+": + case "-": + case "@": + case "\t": + case "\r": + case "\uFF1D": // Unicode '=' + case "\uFF0B": // Unicode '+' + case "\uFF0D": // Unicode '-' + case "\uFF20": // Unicode '@' + value = `'${value}`; + break; } } - const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch; - if(shouldQuote === true && containsEscape === true){ - const regexp = escape === '\\' - ? new RegExp(escape + escape, 'g') - : new RegExp(escape, 'g'); + const shouldQuote = + containsQuote === true || + containsdelimiter || + containsRecordDelimiter || + quoted || + quotedString || + quotedMatch; + if (shouldQuote === true && containsEscape === true) { + const regexp = + escape === "\\" + ? new RegExp(escape + escape, "g") + : new RegExp(escape, "g"); value = value.replace(regexp, escape + escape); } - if(containsQuote === true){ - const regexp = new RegExp(quote,'g'); + if (containsQuote === true) { + const regexp = new RegExp(quote, "g"); value = value.replace(regexp, escape + quote); } - if(shouldQuote === true){ + if (shouldQuote === true) { value = quote + value + quote; } csvrecord += value; - }else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){ + } else if ( + quoted_empty === true || + (field === "" && quoted_string === true && quoted_empty !== false) + ) { csvrecord += quote + quote; } - if(i !== record.length - 1){ + if (i !== record.length - 1) { csvrecord += delimiter; } } return [undefined, csvrecord]; }, - bom: function(push){ - if(this.options.bom !== true){ + bom: function (push) { + if (this.options.bom !== true) { return; } push(bom_utf8); }, - headers: function(push){ - if(this.options.header === false){ + headers: function (push) { + if (this.options.header === false) { return; } - if(this.options.columns === undefined){ + if (this.options.columns === undefined) { return; } let err; - let headers = this.options.columns.map(column => column.header); - if(this.options.eof){ + let headers = this.options.columns.map((column) => column.header); + if (this.options.eof) { [err, headers] = this.stringify(headers, true); headers += this.options.record_delimiter; - }else { + } else { [err, headers] = this.stringify(headers); } - if(err) return err; + if (err) return err; push(headers); }, - __cast: function(value, context){ + __cast: function (value, context) { const type = typeof value; - try{ - if(type === 'string'){ // Fine for 99% of the cases + try { + if (type === "string") { + // Fine for 99% of the cases return [undefined, this.options.cast.string(value, context)]; - }else if(type === 'bigint'){ + } else if (type === "bigint") { return [undefined, this.options.cast.bigint(value, context)]; - }else if(type === 'number'){ + } else if (type === "number") { return [undefined, this.options.cast.number(value, context)]; - }else if(type === 'boolean'){ + } else if (type === "boolean") { return [undefined, this.options.cast.boolean(value, context)]; - }else if(value instanceof Date){ + } else if (value instanceof Date) { return [undefined, this.options.cast.date(value, context)]; - }else if(type === 'object' && value !== null){ + } else if (type === "object" && value !== null) { return [undefined, this.options.cast.object(value, context)]; - }else { + } else { return [undefined, value, value]; } - }catch(err){ + } catch (err) { return [err]; } - } + }, }; }; - const stringify = function(records, opts={}){ + const stringify = function (records, opts = {}) { const data = []; const [err, options] = normalize_options(opts); - if(err !== undefined) throw err; + if (err !== undefined) throw err; const state = { - stop: false + stop: false, }; // Information const info = { - records: 0 + records: 0, }; const api = stringifier(options, state, info); - for(const record of records){ - const err = api.__transform(record, function(record){ + for (const record of records) { + const err = api.__transform(record, function (record) { data.push(record); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - if(data.length === 0){ + if (data.length === 0) { api.bom((d) => { data.push(d); }); const err = api.headers((headers) => { data.push(headers); }); - if(err !== undefined) throw err; + if (err !== undefined) throw err; } - return data.join(''); + return data.join(""); }; - const Transformer = function(options = {}, handler){ + /* + Stream Transform + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -7422,20 +8014,21 @@ util.inherits(Transformer, Stream.Transform); - Transformer.prototype._transform = function(chunk, _, cb){ + Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -7447,93 +8040,103 @@ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; - Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ + Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; - Transformer.prototype.__done = function(err, chunks, cb){ + Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; - const transform = function(){ + /* + Stream Transform - sync module + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const transform = function () { // Import arguments normalization let handler, records; let options = {}; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { handler = argument; - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } // Validate arguments let expected_handler_length = 1; - if(options.params){ + if (options.params) { expected_handler_length++; } - if(handler.length > expected_handler_length){ - throw Error('Invalid Handler: only synchonous handlers are supported'); + if (handler.length > expected_handler_length) { + throw Error("Invalid Handler: only synchonous handlers are supported"); } // Start transformation const chunks = []; const transformer = new Transformer(options, handler); - transformer.push = function(chunk){ + transformer.push = function (chunk) { chunks.push(chunk); }; - for(const record of records){ - transformer._transform(record, null, function(){}); + for (const record of records) { + transformer._transform(record, null, function () {}); } - return chunks; + return chunks; }; exports.generate = generate; diff --git a/packages/csv/eslint.config.js b/packages/csv/eslint.config.js new file mode 100644 index 000000000..c129c277f --- /dev/null +++ b/packages/csv/eslint.config.js @@ -0,0 +1,16 @@ +import globals from "globals"; +import js from "@eslint/js"; +import mocha from "eslint-plugin-mocha"; +import prettier from "eslint-plugin-prettier/recommended"; + +export default [ + { + ignores: ["dist/**"], + }, + { + languageOptions: { globals: { ...globals.node } }, + }, + js.configs.recommended, + mocha.configs.flat.recommended, + prettier, +]; diff --git a/packages/csv/lib/index.js b/packages/csv/lib/index.js index b8e53297a..b8b4b7e42 100644 --- a/packages/csv/lib/index.js +++ b/packages/csv/lib/index.js @@ -1,9 +1,8 @@ - // Alias to the modules exposing the stream and callback APIs -import { generate } from 'csv-generate'; -import { parse } from 'csv-parse'; -import { transform } from 'stream-transform'; -import { stringify } from 'csv-stringify'; +import { generate } from "csv-generate"; +import { parse } from "csv-parse"; +import { transform } from "stream-transform"; +import { stringify } from "csv-stringify"; export { generate, parse, stringify, transform }; diff --git a/packages/csv/lib/sync.js b/packages/csv/lib/sync.js index 3709f75e6..8bf3f41b7 100644 --- a/packages/csv/lib/sync.js +++ b/packages/csv/lib/sync.js @@ -1,9 +1,8 @@ - // Alias to the modules exposing the sync API -import { generate } from 'csv-generate/sync'; -import { parse } from 'csv-parse/sync'; -import { stringify } from 'csv-stringify/sync'; -import { transform } from 'stream-transform/sync'; +import { generate } from "csv-generate/sync"; +import { parse } from "csv-parse/sync"; +import { stringify } from "csv-stringify/sync"; +import { transform } from "stream-transform/sync"; export { generate, parse, stringify, transform }; diff --git a/packages/csv/package.json b/packages/csv/package.json index 28f4bcbb9..771a69981 100644 --- a/packages/csv/package.json +++ b/packages/csv/package.json @@ -29,14 +29,18 @@ "stream-transform": "^3.3.2" }, "devDependencies": { - "@rollup/plugin-eslint": "^9.0.4", - "@rollup/plugin-node-resolve": "^15.2.1", + "@eslint/js": "^9.9.1", + "@rollup/plugin-node-resolve": "^15.2.3", "@types/mocha": "^10.0.7", "@types/node": "^22.5.0", "coffeescript": "~2.7.0", - "eslint": "^8.47.0", "each": "^2.7.0", + "eslint": "^9.9.1", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-mocha": "^10.5.0", + "eslint-plugin-prettier": "^5.2.1", "mocha": "~10.7.3", + "prettier": "^3.3.3", "rollup": "^4.21.0", "rollup-plugin-node-builtins": "^2.1.2", "rollup-plugin-node-globals": "^1.4.0", @@ -105,11 +109,8 @@ "build:rollup": "npx rollup -c", "build:ts": "cp lib/index.d.ts dist/cjs/index.d.cts && cp lib/sync.d.ts dist/cjs/sync.d.cts && cp lib/*.ts dist/esm", "postbuild:ts": "find dist/cjs -name '*.d.cts' -exec sh -c \"sed -i \"s/\\.js'/\\.cjs'/g\" {} || sed -i '' \"s/\\.js'/\\.cjs'/g\" {}\" \\;", - "lint": "npm run lint:lib && npm run lint:samples && npm run lint:test", - "postlint": "tsc --noEmit true", - "lint:lib": "eslint --fix lib/*.js", - "lint:samples": "eslint --fix samples/*.js", - "lint:test": "coffeelint --fix test/*.coffee", + "lint:check": "eslint && tsc --noEmit true", + "lint:fix": "eslint --fix && tsc --noEmit true", "preversion": "npm run build && git add dist", "pretest": "npm run build", "test": "mocha 'test/**/*.{coffee,ts}'", diff --git a/packages/csv/rollup.config.js b/packages/csv/rollup.config.js index 0263b9dcf..3bd250a50 100644 --- a/packages/csv/rollup.config.js +++ b/packages/csv/rollup.config.js @@ -1,82 +1,102 @@ +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import globals from "rollup-plugin-node-globals"; +import builtins from "rollup-plugin-node-builtins"; +// import eslint from "@rollup/plugin-eslint"; -import { nodeResolve } from '@rollup/plugin-node-resolve'; -import globals from 'rollup-plugin-node-globals'; -import builtins from 'rollup-plugin-node-builtins'; -import eslint from '@rollup/plugin-eslint'; - -export default [{ - onwarn: function(warning, rollupWarn) { - // Not much we can do, Node.js `readable-stream/readable.js` and - // `readable-stream/duplex.js` from `rollup-plugin-node-builtins` raise this - // issue. - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - rollupWarn(warning); - }, - input: 'lib/index.js', - output: [ - { - file: `dist/esm/index.js`, - format: 'esm' - }, - { - file: `dist/iife/index.js`, - format: 'iife', - name: 'csv' +export default [ + { + onwarn: function (warning, rollupWarn) { + // Not much we can do, Node.js `readable-stream/readable.js` and + // `readable-stream/duplex.js` from `rollup-plugin-node-builtins` raise this + // issue. + if (warning.code === "CIRCULAR_DEPENDENCY") return; + rollupWarn(warning); }, - { - file: `dist/umd/index.js`, - format: 'umd', - name: 'csv' - }, - ], - plugins: [eslint({ - fix: true, - }), globals(), builtins(), nodeResolve()], -}, { - input: 'lib/index.js', - output: [ - { - file: `dist/cjs/index.cjs`, - format: 'cjs' - }, - ], - plugins: [eslint({ - fix: true, - }), nodeResolve()], -}, { - onwarn: function(warning, rollupWarn) { - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - rollupWarn(warning); + input: "lib/index.js", + output: [ + { + file: `dist/esm/index.js`, + format: "esm", + }, + { + file: `dist/iife/index.js`, + format: "iife", + name: "csv", + }, + { + file: `dist/umd/index.js`, + format: "umd", + name: "csv", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + globals(), + builtins(), + nodeResolve(), + ], }, - input: 'lib/sync.js', - output: [ - { - file: `dist/esm/sync.js`, - format: 'esm' - }, - { - file: `dist/iife/sync.js`, - format: 'iife', - name: 'csv_sync' - }, - { - file: `dist/umd/sync.js`, - format: 'umd', - name: 'csv_sync' - }, - ], - plugins: [eslint({ - fix: true, - }), globals(), builtins(), nodeResolve()], -}, { - input: 'lib/sync.js', - output: [ - { - file: `dist/cjs/sync.cjs`, - format: 'cjs' + { + input: "lib/index.js", + output: [ + { + file: `dist/cjs/index.cjs`, + format: "cjs", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + nodeResolve(), + ], + }, + { + onwarn: function (warning, rollupWarn) { + if (warning.code === "CIRCULAR_DEPENDENCY") return; + rollupWarn(warning); }, - ], - plugins: [eslint({ - fix: true, - }), nodeResolve()], -}]; + input: "lib/sync.js", + output: [ + { + file: `dist/esm/sync.js`, + format: "esm", + }, + { + file: `dist/iife/sync.js`, + format: "iife", + name: "csv_sync", + }, + { + file: `dist/umd/sync.js`, + format: "umd", + name: "csv_sync", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + globals(), + builtins(), + nodeResolve(), + ], + }, + { + input: "lib/sync.js", + output: [ + { + file: `dist/cjs/sync.cjs`, + format: "cjs", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + nodeResolve(), + ], + }, +]; diff --git a/packages/csv/samples/callback.js b/packages/csv/samples/callback.js index e99457015..43228416c 100644 --- a/packages/csv/samples/callback.js +++ b/packages/csv/samples/callback.js @@ -1,16 +1,21 @@ - // Import the package -import {generate, parse, transform, stringify} from 'csv'; +import { generate, parse, transform, stringify } from "csv"; // Run the pipeline -generate({seed: 1, columns: 2, length: 20}, function(err, data){ - parse(data, function(err, data){ - transform(data, function(data){ - return data.map(function(value){return value.toUpperCase();}); - }, function(err, data){ - stringify(data, function(err, data){ - process.stdout.write(data); - }); - }); +generate({ seed: 1, columns: 2, length: 20 }, function (err, data) { + parse(data, function (err, data) { + transform( + data, + function (data) { + return data.map(function (value) { + return value.toUpperCase(); + }); + }, + function (err, data) { + stringify(data, function (err, data) { + process.stdout.write(data); + }); + }, + ); }); }); diff --git a/packages/csv/samples/example.fs.js b/packages/csv/samples/example.fs.js index 51c32f2c4..74c965404 100644 --- a/packages/csv/samples/example.fs.js +++ b/packages/csv/samples/example.fs.js @@ -6,7 +6,7 @@ import { parse, transform, stringify } from "csv"; const __dirname = new URL(".", import.meta.url).pathname; await fs.promises.writeFile( `${__dirname}/example.fs.input.csv`, - "a,b,c\n1,2,3" + "a,b,c\n1,2,3", ); await finished( @@ -15,10 +15,10 @@ await finished( .pipe(parse()) .pipe(transform((record) => record.reverse())) .pipe(stringify()) - .pipe(fs.createWriteStream(`${__dirname}/example.fs.output.csv`)) + .pipe(fs.createWriteStream(`${__dirname}/example.fs.output.csv`)), ); assert.equal( await fs.promises.readFile(`${__dirname}/example.fs.output.csv`, "utf8"), - "c,b,a\n3,2,1\n" + "c,b,a\n3,2,1\n", ); diff --git a/packages/csv/samples/pipe.js b/packages/csv/samples/pipe.js index ad41fc412..13a4367f0 100644 --- a/packages/csv/samples/pipe.js +++ b/packages/csv/samples/pipe.js @@ -1,27 +1,26 @@ - // Import the package -import * as csv from 'csv'; +import * as csv from "csv"; // Run the pipeline csv // Generate 20 records .generate({ - delimiter: '|', - length: 20 + delimiter: "|", + length: 20, }) // Transform CSV data into records - .pipe(csv.parse({ - delimiter: '|' - })) + .pipe( + csv.parse({ + delimiter: "|", + }), + ) // Transform each value into uppercase - .pipe(csv.transform((record) => - record.map((value) => - value.toUpperCase() - ) - )) + .pipe(csv.transform((record) => record.map((value) => value.toUpperCase()))) // Convert objects into a stream - .pipe(csv.stringify({ - quoted: true - })) + .pipe( + csv.stringify({ + quoted: true, + }), + ) // Print the CSV stream to stdout .pipe(process.stdout); diff --git a/packages/csv/samples/stream.js b/packages/csv/samples/stream.js index 0b702b108..4fa9b971b 100644 --- a/packages/csv/samples/stream.js +++ b/packages/csv/samples/stream.js @@ -1,57 +1,62 @@ - // Import the package -import {generate, parse, transform, stringify} from 'csv'; +import { generate, parse, transform, stringify } from "csv"; let i = 0; -const generator = generate({seed: 1, columns: 2, length: 20}); +const generator = generate({ seed: 1, columns: 2, length: 20 }); const parser = parse(); -const transformer = transform(function(data){ +const transformer = transform(function (data) { i++; - return data.map(function(value){return value.toUpperCase();}); + return data.map(function (value) { + return value.toUpperCase(); + }); }); const stringifier = stringify(); // Read generated CSV data and send it to the parser -generator.on('readable', function(){ - let data; while((data = generator.read()) !== null){ +generator.on("readable", function () { + let data; + while ((data = generator.read()) !== null) { parser.write(data); } }); // When generation is over, close the parser -generator.on('end', function(){ +generator.on("end", function () { parser.end(); }); // Read parsed records and send them to the transformer -parser.on('readable', function(){ - let data; while((data = parser.read()) !== null){ +parser.on("readable", function () { + let data; + while ((data = parser.read()) !== null) { transformer.write(data); } }); // When parsing is over, close the transformer -parser.on('end', function(){ +parser.on("end", function () { transformer.end(); }); // Read transformed records and send them to the stringifier -transformer.on('readable', function(){ - let data; while((data = transformer.read()) !== null){ +transformer.on("readable", function () { + let data; + while ((data = transformer.read()) !== null) { stringifier.write(data); } }); // When transformation is over, close the stringifier -transformer.on('end', function(){ +transformer.on("end", function () { stringifier.end(); }); // Read CSV data and print it to stdout -stringifier.on('readable', function(){ - let data; while((data = stringifier.read()) !== null){ +stringifier.on("readable", function () { + let data; + while ((data = stringifier.read()) !== null) { process.stdout.write(data); } }); // When stringifying is over, print a summary to stderr -generator.on('close', function(){ - process.stderr.write('=> ' + i + ' records\n'); +generator.on("close", function () { + process.stderr.write("=> " + i + " records\n"); }); diff --git a/packages/csv/samples/sync.js b/packages/csv/samples/sync.js index 5d55b8174..0204a25e4 100644 --- a/packages/csv/samples/sync.js +++ b/packages/csv/samples/sync.js @@ -5,7 +5,7 @@ import { generate, parse, transform, stringify } from "csv/sync"; const input = generate({ seed: 1, columns: 2, length: 2 }); const rawRecords = parse(input); const refinedRecords = transform(rawRecords, (data) => - data.map((value) => value.toUpperCase()) + data.map((value) => value.toUpperCase()), ); const output = stringify(refinedRecords); // Print the final result diff --git a/packages/stream-transform/.eslintrc.yml b/packages/stream-transform/.eslintrc.yml deleted file mode 100644 index 4581986eb..000000000 --- a/packages/stream-transform/.eslintrc.yml +++ /dev/null @@ -1,21 +0,0 @@ -env: - commonjs: true - es6: true - node: true -extends: "eslint:recommended" -globals: - Atomics: "readonly" - SharedArrayBuffer: "readonly" -parserOptions: - ecmaVersion: "latest" - sourceType: "module" -rules: - no-var: "error" - semi: "error" - indent: ["error", 2] - linebreak-style: ["error", "unix"] - no-multi-spaces: "error" - space-in-parens: "error" - no-multiple-empty-lines: "error" - prefer-const: "error" - no-use-before-define: "error" diff --git a/packages/stream-transform/.travis.yml b/packages/stream-transform/.travis.yml deleted file mode 100644 index b33d1432c..000000000 --- a/packages/stream-transform/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: node_js -node_js: - - "7" - - "8" - - "10" - - "11" diff --git a/packages/stream-transform/coffeelint.json b/packages/stream-transform/coffeelint.json deleted file mode 100644 index db57f258d..000000000 --- a/packages/stream-transform/coffeelint.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "arrow_spacing": { - "level": "ignore" - }, - "braces_spacing": { - "level": "ignore", - "spaces": 0, - "empty_object_spaces": 0 - }, - "camel_case_classes": { - "level": "error" - }, - "coffeescript_error": { - "level": "error" - }, - "colon_assignment_spacing": { - "level": "ignore", - "spacing": { - "left": 0, - "right": 0 - } - }, - "cyclomatic_complexity": { - "level": "ignore", - "value": 10 - }, - "duplicate_key": { - "level": "error" - }, - "empty_constructor_needs_parens": { - "level": "ignore" - }, - "ensure_comprehensions": { - "level": "warn" - }, - "eol_last": { - "level": "ignore" - }, - "indentation": { - "value": 2, - "level": "error" - }, - "line_endings": { - "level": "error", - "value": "unix" - }, - "max_line_length": { - "value": 80, - "level": "ignore", - "limitComments": true - }, - "missing_fat_arrows": { - "level": "ignore", - "is_strict": false - }, - "newlines_after_classes": { - "value": 3, - "level": "ignore" - }, - "no_backticks": { - "level": "error" - }, - "no_debugger": { - "level": "warn", - "console": false - }, - "no_empty_functions": { - "level": "ignore" - }, - "no_empty_param_list": { - "level": "ignore" - }, - "no_implicit_braces": { - "level": "ignore", - "strict": true - }, - "no_implicit_parens": { - "level": "ignore", - "strict": true - }, - "no_interpolation_in_single_quotes": { - "level": "ignore" - }, - "no_nested_string_interpolation": { - "level": "warn" - }, - "no_plusplus": { - "level": "ignore" - }, - "no_private_function_fat_arrows": { - "level": "warn" - }, - "no_stand_alone_at": { - "level": "ignore" - }, - "no_tabs": { - "level": "error" - }, - "no_this": { - "level": "ignore" - }, - "no_throwing_strings": { - "level": "error" - }, - "no_trailing_semicolons": { - "level": "error" - }, - "no_trailing_whitespace": { - "level": "error", - "allowed_in_comments": false, - "allowed_in_empty_lines": true - }, - "no_unnecessary_double_quotes": { - "level": "ignore" - }, - "no_unnecessary_fat_arrows": { - "level": "warn" - }, - "non_empty_constructor_needs_parens": { - "level": "ignore" - }, - "prefer_english_operator": { - "level": "ignore", - "doubleNotLevel": "ignore" - }, - "space_operators": { - "level": "ignore" - }, - "spacing_after_comma": { - "level": "ignore" - }, - "transform_messes_up_line_numbers": { - "level": "warn" - } -} diff --git a/packages/stream-transform/dist/cjs/index.cjs b/packages/stream-transform/dist/cjs/index.cjs index 1cc64b333..6f232e252 100644 --- a/packages/stream-transform/dist/cjs/index.cjs +++ b/packages/stream-transform/dist/cjs/index.cjs @@ -3,16 +3,24 @@ var stream = require('stream'); var util = require('util'); -const Transformer = function(options = {}, handler){ +/* +Stream Transform + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -28,20 +36,21 @@ const Transformer = function(options = {}, handler){ util.inherits(Transformer, stream.Transform); -Transformer.prototype._transform = function(chunk, _, cb){ +Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -53,108 +62,111 @@ Transformer.prototype._transform = function(chunk, _, cb){ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; -Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ +Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; -Transformer.prototype.__done = function(err, chunks, cb){ +Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; -const transform = function(){ +const transform = function () { let options = {}; let callback, handler, records; - for(let i = 0; i< arguments.length; i++){ + for (let i = 0; i < arguments.length; i++) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { if (handler && i === arguments.length - 1) { callback = argument; } else { handler = argument; } - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } const transformer = new Transformer(options, handler); let error = false; if (records) { - const writer = function(){ - for(const record of records){ - if(error) break; + const writer = function () { + for (const record of records) { + if (error) break; transformer.write(record); } transformer.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } - if(callback || options.consume) { + if (callback || options.consume) { const result = []; - transformer.on('readable', function(){ - let record; while((record = transformer.read()) !== null){ - if(callback){ + transformer.on("readable", function () { + let record; + while ((record = transformer.read()) !== null) { + if (callback) { result.push(record); } } }); - transformer.on('error', function(err){ + transformer.on("error", function (err) { error = true; if (callback) callback(err); }); - transformer.on('end', function(){ + transformer.on("end", function () { if (callback && !error) callback(null, result); }); } diff --git a/packages/stream-transform/dist/cjs/sync.cjs b/packages/stream-transform/dist/cjs/sync.cjs index 85f1eb60b..1be3e8278 100644 --- a/packages/stream-transform/dist/cjs/sync.cjs +++ b/packages/stream-transform/dist/cjs/sync.cjs @@ -3,16 +3,24 @@ var stream = require('stream'); var util = require('util'); -const Transformer = function(options = {}, handler){ +/* +Stream Transform + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -28,20 +36,21 @@ const Transformer = function(options = {}, handler){ util.inherits(Transformer, stream.Transform); -Transformer.prototype._transform = function(chunk, _, cb){ +Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -53,93 +62,103 @@ Transformer.prototype._transform = function(chunk, _, cb){ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; -Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ +Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; -Transformer.prototype.__done = function(err, chunks, cb){ +Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; -const transform = function(){ +/* +Stream Transform - sync module + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const transform = function () { // Import arguments normalization let handler, records; let options = {}; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { handler = argument; - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } // Validate arguments let expected_handler_length = 1; - if(options.params){ + if (options.params) { expected_handler_length++; } - if(handler.length > expected_handler_length){ - throw Error('Invalid Handler: only synchonous handlers are supported'); + if (handler.length > expected_handler_length) { + throw Error("Invalid Handler: only synchonous handlers are supported"); } // Start transformation const chunks = []; const transformer = new Transformer(options, handler); - transformer.push = function(chunk){ + transformer.push = function (chunk) { chunks.push(chunk); }; - for(const record of records){ - transformer._transform(record, null, function(){}); + for (const record of records) { + transformer._transform(record, null, function () {}); } - return chunks; + return chunks; }; exports.transform = transform; diff --git a/packages/stream-transform/dist/esm/index.js b/packages/stream-transform/dist/esm/index.js index 8395fd2e8..9fa056bf9 100644 --- a/packages/stream-transform/dist/esm/index.js +++ b/packages/stream-transform/dist/esm/index.js @@ -28,7 +28,7 @@ EventEmitter.init = function() { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5194,16 +5194,24 @@ Stream.prototype.pipe = function(dest, options) { return dest; }; -const Transformer = function(options = {}, handler){ +/* +Stream Transform + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -5219,20 +5227,21 @@ const Transformer = function(options = {}, handler){ util.inherits(Transformer, Stream.Transform); -Transformer.prototype._transform = function(chunk, _, cb){ +Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -5244,108 +5253,111 @@ Transformer.prototype._transform = function(chunk, _, cb){ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; -Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ +Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; -Transformer.prototype.__done = function(err, chunks, cb){ +Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; -const transform = function(){ +const transform = function () { let options = {}; let callback, handler, records; - for(let i = 0; i< arguments.length; i++){ + for (let i = 0; i < arguments.length; i++) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { if (handler && i === arguments.length - 1) { callback = argument; } else { handler = argument; } - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } const transformer = new Transformer(options, handler); let error = false; if (records) { - const writer = function(){ - for(const record of records){ - if(error) break; + const writer = function () { + for (const record of records) { + if (error) break; transformer.write(record); } transformer.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } - if(callback || options.consume) { + if (callback || options.consume) { const result = []; - transformer.on('readable', function(){ - let record; while((record = transformer.read()) !== null){ - if(callback){ + transformer.on("readable", function () { + let record; + while ((record = transformer.read()) !== null) { + if (callback) { result.push(record); } } }); - transformer.on('error', function(err){ + transformer.on("error", function (err) { error = true; if (callback) callback(err); }); - transformer.on('end', function(){ + transformer.on("end", function () { if (callback && !error) callback(null, result); }); } diff --git a/packages/stream-transform/dist/esm/sync.js b/packages/stream-transform/dist/esm/sync.js index a78312e88..b16eb1094 100644 --- a/packages/stream-transform/dist/esm/sync.js +++ b/packages/stream-transform/dist/esm/sync.js @@ -28,7 +28,7 @@ EventEmitter.init = function() { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5194,16 +5194,24 @@ Stream.prototype.pipe = function(dest, options) { return dest; }; -const Transformer = function(options = {}, handler){ +/* +Stream Transform + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -5219,20 +5227,21 @@ const Transformer = function(options = {}, handler){ util.inherits(Transformer, Stream.Transform); -Transformer.prototype._transform = function(chunk, _, cb){ +Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -5244,93 +5253,103 @@ Transformer.prototype._transform = function(chunk, _, cb){ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; -Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ +Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; -Transformer.prototype.__done = function(err, chunks, cb){ +Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; -const transform = function(){ +/* +Stream Transform - sync module + +Please look at the [project documentation](https://csv.js.org/transform/) for +additional information. +*/ + + +const transform = function () { // Import arguments normalization let handler, records; let options = {}; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { handler = argument; - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } // Validate arguments let expected_handler_length = 1; - if(options.params){ + if (options.params) { expected_handler_length++; } - if(handler.length > expected_handler_length){ - throw Error('Invalid Handler: only synchonous handlers are supported'); + if (handler.length > expected_handler_length) { + throw Error("Invalid Handler: only synchonous handlers are supported"); } // Start transformation const chunks = []; const transformer = new Transformer(options, handler); - transformer.push = function(chunk){ + transformer.push = function (chunk) { chunks.push(chunk); }; - for(const record of records){ - transformer._transform(record, null, function(){}); + for (const record of records) { + transformer._transform(record, null, function () {}); } - return chunks; + return chunks; }; export { transform }; diff --git a/packages/stream-transform/dist/iife/index.js b/packages/stream-transform/dist/iife/index.js index 402fe419a..4f79bdd75 100644 --- a/packages/stream-transform/dist/iife/index.js +++ b/packages/stream-transform/dist/iife/index.js @@ -31,7 +31,7 @@ var stream_transform = (function (exports) { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5197,16 +5197,24 @@ var stream_transform = (function (exports) { return dest; }; - const Transformer = function(options = {}, handler){ + /* + Stream Transform + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -5222,20 +5230,21 @@ var stream_transform = (function (exports) { util.inherits(Transformer, Stream.Transform); - Transformer.prototype._transform = function(chunk, _, cb){ + Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -5247,108 +5256,111 @@ var stream_transform = (function (exports) { } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; - Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ + Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; - Transformer.prototype.__done = function(err, chunks, cb){ + Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; - const transform = function(){ + const transform = function () { let options = {}; let callback, handler, records; - for(let i = 0; i< arguments.length; i++){ + for (let i = 0; i < arguments.length; i++) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { if (handler && i === arguments.length - 1) { callback = argument; } else { handler = argument; } - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } const transformer = new Transformer(options, handler); let error = false; if (records) { - const writer = function(){ - for(const record of records){ - if(error) break; + const writer = function () { + for (const record of records) { + if (error) break; transformer.write(record); } transformer.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } - if(callback || options.consume) { + if (callback || options.consume) { const result = []; - transformer.on('readable', function(){ - let record; while((record = transformer.read()) !== null){ - if(callback){ + transformer.on("readable", function () { + let record; + while ((record = transformer.read()) !== null) { + if (callback) { result.push(record); } } }); - transformer.on('error', function(err){ + transformer.on("error", function (err) { error = true; if (callback) callback(err); }); - transformer.on('end', function(){ + transformer.on("end", function () { if (callback && !error) callback(null, result); }); } diff --git a/packages/stream-transform/dist/iife/sync.js b/packages/stream-transform/dist/iife/sync.js index ba465edbf..ca4cc08c7 100644 --- a/packages/stream-transform/dist/iife/sync.js +++ b/packages/stream-transform/dist/iife/sync.js @@ -31,7 +31,7 @@ var stream_transform_sync = (function (exports) { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5197,16 +5197,24 @@ var stream_transform_sync = (function (exports) { return dest; }; - const Transformer = function(options = {}, handler){ + /* + Stream Transform + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -5222,20 +5230,21 @@ var stream_transform_sync = (function (exports) { util.inherits(Transformer, Stream.Transform); - Transformer.prototype._transform = function(chunk, _, cb){ + Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -5247,93 +5256,103 @@ var stream_transform_sync = (function (exports) { } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; - Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ + Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; - Transformer.prototype.__done = function(err, chunks, cb){ + Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; - const transform = function(){ + /* + Stream Transform - sync module + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const transform = function () { // Import arguments normalization let handler, records; let options = {}; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { handler = argument; - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } // Validate arguments let expected_handler_length = 1; - if(options.params){ + if (options.params) { expected_handler_length++; } - if(handler.length > expected_handler_length){ - throw Error('Invalid Handler: only synchonous handlers are supported'); + if (handler.length > expected_handler_length) { + throw Error("Invalid Handler: only synchonous handlers are supported"); } // Start transformation const chunks = []; const transformer = new Transformer(options, handler); - transformer.push = function(chunk){ + transformer.push = function (chunk) { chunks.push(chunk); }; - for(const record of records){ - transformer._transform(record, null, function(){}); + for (const record of records) { + transformer._transform(record, null, function () {}); } - return chunks; + return chunks; }; exports.transform = transform; diff --git a/packages/stream-transform/dist/umd/index.js b/packages/stream-transform/dist/umd/index.js index 26b5e9134..3992db383 100644 --- a/packages/stream-transform/dist/umd/index.js +++ b/packages/stream-transform/dist/umd/index.js @@ -34,7 +34,7 @@ this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5200,16 +5200,24 @@ return dest; }; - const Transformer = function(options = {}, handler){ + /* + Stream Transform + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -5225,20 +5233,21 @@ util.inherits(Transformer, Stream.Transform); - Transformer.prototype._transform = function(chunk, _, cb){ + Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -5250,108 +5259,111 @@ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; - Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ + Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; - Transformer.prototype.__done = function(err, chunks, cb){ + Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; - const transform = function(){ + const transform = function () { let options = {}; let callback, handler, records; - for(let i = 0; i< arguments.length; i++){ + for (let i = 0; i < arguments.length; i++) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { if (handler && i === arguments.length - 1) { callback = argument; } else { handler = argument; } - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } const transformer = new Transformer(options, handler); let error = false; if (records) { - const writer = function(){ - for(const record of records){ - if(error) break; + const writer = function () { + for (const record of records) { + if (error) break; transformer.write(record); } transformer.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else { + } else { setTimeout(writer, 0); } } - if(callback || options.consume) { + if (callback || options.consume) { const result = []; - transformer.on('readable', function(){ - let record; while((record = transformer.read()) !== null){ - if(callback){ + transformer.on("readable", function () { + let record; + while ((record = transformer.read()) !== null) { + if (callback) { result.push(record); } } }); - transformer.on('error', function(err){ + transformer.on("error", function (err) { error = true; if (callback) callback(err); }); - transformer.on('end', function(){ + transformer.on("end", function () { if (callback && !error) callback(null, result); }); } diff --git a/packages/stream-transform/dist/umd/sync.js b/packages/stream-transform/dist/umd/sync.js index 697be5d6f..c5e979980 100644 --- a/packages/stream-transform/dist/umd/sync.js +++ b/packages/stream-transform/dist/umd/sync.js @@ -34,7 +34,7 @@ this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. - if (domain.active ) ; + if (domain.active) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { @@ -5200,16 +5200,24 @@ return dest; }; - const Transformer = function(options = {}, handler){ + /* + Stream Transform + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -5225,20 +5233,21 @@ util.inherits(Transformer, Stream.Transform); - Transformer.prototype._transform = function(chunk, _, cb){ + Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -5250,93 +5259,103 @@ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else { - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; - Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ + Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else { - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; - Transformer.prototype.__done = function(err, chunks, cb){ + Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; - const transform = function(){ + /* + Stream Transform - sync module + + Please look at the [project documentation](https://csv.js.org/transform/) for + additional information. + */ + + + const transform = function () { // Import arguments normalization let handler, records; let options = {}; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { handler = argument; - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } // Validate arguments let expected_handler_length = 1; - if(options.params){ + if (options.params) { expected_handler_length++; } - if(handler.length > expected_handler_length){ - throw Error('Invalid Handler: only synchonous handlers are supported'); + if (handler.length > expected_handler_length) { + throw Error("Invalid Handler: only synchonous handlers are supported"); } // Start transformation const chunks = []; const transformer = new Transformer(options, handler); - transformer.push = function(chunk){ + transformer.push = function (chunk) { chunks.push(chunk); }; - for(const record of records){ - transformer._transform(record, null, function(){}); + for (const record of records) { + transformer._transform(record, null, function () {}); } - return chunks; + return chunks; }; exports.transform = transform; diff --git a/packages/stream-transform/eslint.config.js b/packages/stream-transform/eslint.config.js new file mode 100644 index 000000000..c129c277f --- /dev/null +++ b/packages/stream-transform/eslint.config.js @@ -0,0 +1,16 @@ +import globals from "globals"; +import js from "@eslint/js"; +import mocha from "eslint-plugin-mocha"; +import prettier from "eslint-plugin-prettier/recommended"; + +export default [ + { + ignores: ["dist/**"], + }, + { + languageOptions: { globals: { ...globals.node } }, + }, + js.configs.recommended, + mocha.configs.flat.recommended, + prettier, +]; diff --git a/packages/stream-transform/lib/index.js b/packages/stream-transform/lib/index.js index b05fad6f9..7cfc43e6e 100644 --- a/packages/stream-transform/lib/index.js +++ b/packages/stream-transform/lib/index.js @@ -1,4 +1,3 @@ - /* Stream Transform @@ -6,19 +5,19 @@ Please look at the [project documentation](https://csv.js.org/transform/) for additional information. */ -import stream from 'stream'; -import util from 'util'; +import stream from "stream"; +import util from "util"; -const Transformer = function(options = {}, handler){ +const Transformer = function (options = {}, handler) { this.options = options; - if(options.consume === undefined || options.consume === null){ + if (options.consume === undefined || options.consume === null) { this.options.consume = false; } this.options.objectMode = true; - if(options.parallel === undefined || options.parallel === null){ + if (options.parallel === undefined || options.parallel === null) { this.options.parallel = 100; } - if(options.params === undefined || options.params === null){ + if (options.params === undefined || options.params === null) { options.params = null; } this.handler = handler; @@ -34,20 +33,21 @@ const Transformer = function(options = {}, handler){ util.inherits(Transformer, stream.Transform); -Transformer.prototype._transform = function(chunk, _, cb){ +Transformer.prototype._transform = function (chunk, _, cb) { this.state.started++; this.state.running++; // Accept additionnal chunks to be processed in parallel - if(!this.state.paused && this.state.running < this.options.parallel){ + if (!this.state.paused && this.state.running < this.options.parallel) { cb(); cb = null; // Cancel further callback execution } try { let l = this.handler.length; - if(this.options.params !== null){ + if (this.options.params !== null) { l--; } - if(l === 1){ // sync + if (l === 1) { + // sync const result = this.handler.call(this, chunk, this.options.params); if (result && result.then) { result.then((result) => { @@ -59,108 +59,111 @@ Transformer.prototype._transform = function(chunk, _, cb){ } else { this.__done(null, [result], cb); } - }else if(l === 2){ // async - const callback = (err, ...chunks) => - this.__done(err, chunks, cb); + } else if (l === 2) { + // async + const callback = (err, ...chunks) => this.__done(err, chunks, cb); this.handler.call(this, chunk, callback, this.options.params); - }else{ - throw Error('Invalid handler arguments'); + } else { + throw Error("Invalid handler arguments"); } return false; } catch (err) { this.__done(err); } }; -Transformer.prototype._flush = function(cb){ - if(this.state.running === 0){ +Transformer.prototype._flush = function (cb) { + if (this.state.running === 0) { cb(); - }else{ - this._ending = function(){ + } else { + this._ending = function () { cb(); }; } }; -Transformer.prototype.__done = function(err, chunks, cb){ +Transformer.prototype.__done = function (err, chunks, cb) { this.state.running--; - if(err){ + if (err) { return this.destroy(err); // return this.emit('error', err); } this.state.finished++; - for(let chunk of chunks){ - if (typeof chunk === 'number'){ + for (let chunk of chunks) { + if (typeof chunk === "number") { chunk = `${chunk}`; } // We dont push empty string // See https://nodejs.org/api/stream.html#stream_readable_push - if(chunk !== undefined && chunk !== null && chunk !== ''){ + if (chunk !== undefined && chunk !== null && chunk !== "") { this.state.paused = !this.push(chunk); } } // Chunk has been processed - if(cb){ + if (cb) { cb(); } - if(this._ending && this.state.running === 0){ + if (this._ending && this.state.running === 0) { this._ending(); } }; -const transform = function(){ +const transform = function () { let options = {}; let callback, handler, records; - for(let i = 0; i< arguments.length; i++){ + for (let i = 0; i < arguments.length; i++) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { if (handler && i === arguments.length - 1) { callback = argument; } else { handler = argument; } - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } const transformer = new Transformer(options, handler); let error = false; if (records) { - const writer = function(){ - for(const record of records){ - if(error) break; + const writer = function () { + for (const record of records) { + if (error) break; transformer.write(record); } transformer.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate - if(typeof setImmediate === 'function'){ + if (typeof setImmediate === "function") { setImmediate(writer); - }else{ + } else { setTimeout(writer, 0); } } - if(callback || options.consume) { + if (callback || options.consume) { const result = []; - transformer.on('readable', function(){ - let record; while((record = transformer.read()) !== null){ - if(callback){ + transformer.on("readable", function () { + let record; + while ((record = transformer.read()) !== null) { + if (callback) { result.push(record); } } }); - transformer.on('error', function(err){ + transformer.on("error", function (err) { error = true; if (callback) callback(err); }); - transformer.on('end', function(){ + transformer.on("end", function () { if (callback && !error) callback(null, result); }); } diff --git a/packages/stream-transform/lib/sync.js b/packages/stream-transform/lib/sync.js index 3212129b4..747d2a686 100644 --- a/packages/stream-transform/lib/sync.js +++ b/packages/stream-transform/lib/sync.js @@ -1,4 +1,3 @@ - /* Stream Transform - sync module @@ -6,48 +5,50 @@ Please look at the [project documentation](https://csv.js.org/transform/) for additional information. */ -import {Transformer} from './index.js'; +import { Transformer } from "./index.js"; -const transform = function(){ +const transform = function () { // Import arguments normalization let handler, records; let options = {}; - for(const i in arguments){ + for (const i in arguments) { const argument = arguments[i]; let type = typeof argument; - if(argument === null){ - type = 'null'; - }else if(type === 'object' && Array.isArray(argument)){ - type = 'array'; + if (argument === null) { + type = "null"; + } else if (type === "object" && Array.isArray(argument)) { + type = "array"; } - if(type === 'array'){ + if (type === "array") { records = argument; - }else if(type === 'object'){ - options = {...argument}; - }else if(type === 'function'){ + } else if (type === "object") { + options = { ...argument }; + } else if (type === "function") { handler = argument; - }else if(type !== 'null'){ - throw new Error(`Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`); + } else if (type !== "null") { + throw new Error( + `Invalid Arguments: got ${JSON.stringify(argument)} at position ${i}`, + ); } } // Validate arguments let expected_handler_length = 1; - if(options.params){ + if (options.params) { expected_handler_length++; } - if(handler.length > expected_handler_length){ - throw Error('Invalid Handler: only synchonous handlers are supported'); + if (handler.length > expected_handler_length) { + throw Error("Invalid Handler: only synchonous handlers are supported"); } // Start transformation const chunks = []; const transformer = new Transformer(options, handler); - transformer.push = function(chunk){ + transformer.push = function (chunk) { chunks.push(chunk); }; - for(const record of records){ - transformer._transform(record, null, function(){}); + for (const record of records) { + transformer._transform(record, null, function () {}); } - return chunks; + return chunks; }; // export default transform diff --git a/packages/stream-transform/package.json b/packages/stream-transform/package.json index 57a254a02..06dc90e02 100644 --- a/packages/stream-transform/package.json +++ b/packages/stream-transform/package.json @@ -12,16 +12,20 @@ ], "author": "David Worms (https://www.adaltas.com)", "devDependencies": { - "@rollup/plugin-eslint": "^9.0.4", - "@rollup/plugin-node-resolve": "^15.2.1", + "@eslint/js": "^9.9.1", + "@rollup/plugin-node-resolve": "^15.2.3", "@types/mocha": "^10.0.7", "@types/node": "^22.5.0", "coffeescript": "~2.7.0", "csv-generate": "^4.4.1", - "eslint": "^8.47.0", "each": "^2.7.0", + "eslint": "^9.9.1", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-mocha": "^10.5.0", + "eslint-plugin-prettier": "^5.2.1", "mocha": "~10.7.3", "pad": "~3.2.0", + "prettier": "^3.3.3", "rollup": "^4.21.0", "rollup-plugin-node-builtins": "^2.1.2", "rollup-plugin-node-globals": "^1.4.0", @@ -87,11 +91,8 @@ "build:rollup": "npx rollup -c", "build:ts": "cp lib/index.d.ts dist/cjs/index.d.cts && cp lib/sync.d.ts dist/cjs/sync.d.cts && cp lib/*.ts dist/esm", "postbuild:ts": "find dist/cjs -name '*.d.cts' -exec sh -c \"sed -i \"s/\\.js'/\\.cjs'/g\" {} || sed -i '' \"s/\\.js'/\\.cjs'/g\" {}\" \\;", - "lint": "npm run lint:lib && npm run lint:samples && npm run lint:test", - "postlint": "tsc --noEmit true", - "lint:lib": "eslint --fix lib/*.js", - "lint:samples": "eslint --fix samples/*.js", - "lint:test": "coffeelint --fix test/*.coffee", + "lint:check": "eslint && tsc --noEmit true", + "lint:fix": "eslint --fix && tsc --noEmit true", "preversion": "npm run build && git add dist", "pretest": "npm run build", "test": "mocha 'test/**/*.{coffee,ts}'", diff --git a/packages/stream-transform/rollup.config.js b/packages/stream-transform/rollup.config.js index 2fde673ec..d6e44c8f4 100644 --- a/packages/stream-transform/rollup.config.js +++ b/packages/stream-transform/rollup.config.js @@ -1,82 +1,102 @@ +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import globals from "rollup-plugin-node-globals"; +import builtins from "rollup-plugin-node-builtins"; +// import eslint from "@rollup/plugin-eslint"; -import { nodeResolve } from '@rollup/plugin-node-resolve'; -import globals from 'rollup-plugin-node-globals'; -import builtins from 'rollup-plugin-node-builtins'; -import eslint from '@rollup/plugin-eslint'; - -export default [{ - onwarn: function(warning, rollupWarn) { - // Not much we can do, Node.js `readable-stream/readable.js` and - // `readable-stream/duplex.js` from `rollup-plugin-node-builtins` raise this - // issue. - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - rollupWarn(warning); - }, - input: 'lib/index.js', - output: [ - { - file: `dist/esm/index.js`, - format: 'esm' - }, - { - file: `dist/iife/index.js`, - format: 'iife', - name: 'stream_transform', +export default [ + { + onwarn: function (warning, rollupWarn) { + // Not much we can do, Node.js `readable-stream/readable.js` and + // `readable-stream/duplex.js` from `rollup-plugin-node-builtins` raise this + // issue. + if (warning.code === "CIRCULAR_DEPENDENCY") return; + rollupWarn(warning); }, - { - file: `dist/umd/index.js`, - name: 'csv', - format: 'umd', - }, - ], - plugins: [eslint({ - fix: true, - }), globals(), builtins(), nodeResolve()], -}, { - input: 'lib/index.js', - output: [ - { - file: `dist/cjs/index.cjs`, - format: 'cjs' - }, - ], - plugins: [eslint({ - fix: true, - }), nodeResolve()], -}, { - onwarn: function(warning, rollupWarn) { - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - rollupWarn(warning); + input: "lib/index.js", + output: [ + { + file: `dist/esm/index.js`, + format: "esm", + }, + { + file: `dist/iife/index.js`, + format: "iife", + name: "stream_transform", + }, + { + file: `dist/umd/index.js`, + name: "csv", + format: "umd", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + globals(), + builtins(), + nodeResolve(), + ], }, - input: 'lib/sync.js', - output: [ - { - file: `dist/esm/sync.js`, - format: 'esm' - }, - { - file: `dist/iife/sync.js`, - format: 'iife', - name: 'stream_transform_sync' - }, - { - file: `dist/umd/sync.js`, - name: 'csv', - format: 'umd' - }, - ], - plugins: [eslint({ - fix: true, - }), globals(), builtins(), nodeResolve()], -}, { - input: 'lib/sync.js', - output: [ - { - file: `dist/cjs/sync.cjs`, - format: 'cjs' + { + input: "lib/index.js", + output: [ + { + file: `dist/cjs/index.cjs`, + format: "cjs", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + nodeResolve(), + ], + }, + { + onwarn: function (warning, rollupWarn) { + if (warning.code === "CIRCULAR_DEPENDENCY") return; + rollupWarn(warning); }, - ], - plugins: [eslint({ - fix: true, - }), nodeResolve()], -}]; + input: "lib/sync.js", + output: [ + { + file: `dist/esm/sync.js`, + format: "esm", + }, + { + file: `dist/iife/sync.js`, + format: "iife", + name: "stream_transform_sync", + }, + { + file: `dist/umd/sync.js`, + name: "csv", + format: "umd", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + globals(), + builtins(), + nodeResolve(), + ], + }, + { + input: "lib/sync.js", + output: [ + { + file: `dist/cjs/sync.cjs`, + format: "cjs", + }, + ], + plugins: [ + // eslint({ + // fix: true, + // }), + nodeResolve(), + ], + }, +]; diff --git a/packages/stream-transform/samples/api.callback.js b/packages/stream-transform/samples/api.callback.js index a13bb89f9..98d5bd388 100644 --- a/packages/stream-transform/samples/api.callback.js +++ b/packages/stream-transform/samples/api.callback.js @@ -1,16 +1,19 @@ +import { transform } from "stream-transform"; +import assert from "node:assert"; -import { transform } from 'stream-transform'; -import assert from 'node:assert'; - -transform([ - ['1','2','3','4'], - ['a','b','c','d'] -], function(record){ - record.push(record.shift()); - return record; -}, function(err, output){ - assert.deepEqual(output, [ - [ '2', '3', '4', '1' ], - [ 'b', 'c', 'd', 'a' ] - ]); -}); +transform( + [ + ["1", "2", "3", "4"], + ["a", "b", "c", "d"], + ], + function (record) { + record.push(record.shift()); + return record; + }, + function (err, output) { + assert.deepEqual(output, [ + ["2", "3", "4", "1"], + ["b", "c", "d", "a"], + ]); + }, +); diff --git a/packages/stream-transform/samples/api.mixed.input.stream.js b/packages/stream-transform/samples/api.mixed.input.stream.js index 03d7ce3e6..ee60b5b6a 100644 --- a/packages/stream-transform/samples/api.mixed.input.stream.js +++ b/packages/stream-transform/samples/api.mixed.input.stream.js @@ -1,19 +1,21 @@ - -import { transform } from 'stream-transform'; -import assert from 'node:assert'; +import { transform } from "stream-transform"; +import assert from "node:assert"; // Create the parser -const transformer = transform(function(record){ - record.push(record.shift()); - return record; -}, function(err, output){ - assert.deepEqual(output, [ - [ '2', '3', '4', '1' ], - [ 'b', 'c', 'd', 'a' ] - ]); -}); +const transformer = transform( + function (record) { + record.push(record.shift()); + return record; + }, + function (err, output) { + assert.deepEqual(output, [ + ["2", "3", "4", "1"], + ["b", "c", "d", "a"], + ]); + }, +); // Write data to the stream -transformer.write(['1','2','3','4']); -transformer.write(['a','b','c','d']); +transformer.write(["1", "2", "3", "4"]); +transformer.write(["a", "b", "c", "d"]); // Close the readable stream transformer.end(); diff --git a/packages/stream-transform/samples/api.mixed.output.stream.js b/packages/stream-transform/samples/api.mixed.output.stream.js index 0223f59c5..269157108 100644 --- a/packages/stream-transform/samples/api.mixed.output.stream.js +++ b/packages/stream-transform/samples/api.mixed.output.stream.js @@ -1,29 +1,29 @@ - -import { transform } from 'stream-transform'; -import assert from 'node:assert'; +import { transform } from "stream-transform"; +import assert from "node:assert"; const records = []; // Create the parser -transform([ - ['1','2','3','4'], - ['a','b','c','d'] -], function(record){ - record.push(record.shift()); - return record; -}) -// Use the readable stream api - .on('readable', function(){ - let record; while ((record = this.read()) !== null) { +transform( + [ + ["1", "2", "3", "4"], + ["a", "b", "c", "d"], + ], + function (record) { + record.push(record.shift()); + return record; + }, +) + // Use the readable stream api + .on("readable", function () { + let record; + while ((record = this.read()) !== null) { records.push(record); } }) -// When we are done, test that the parsed records matched what expected - .on('end', function(){ - assert.deepStrictEqual( - records, - [ - [ '2', '3', '4', '1' ], - [ 'b', 'c', 'd', 'a' ] - ] - ); + // When we are done, test that the parsed records matched what expected + .on("end", function () { + assert.deepStrictEqual(records, [ + ["2", "3", "4", "1"], + ["b", "c", "d", "a"], + ]); }); diff --git a/packages/stream-transform/samples/api.stream.js b/packages/stream-transform/samples/api.stream.js index 963086e7e..090b838af 100644 --- a/packages/stream-transform/samples/api.stream.js +++ b/packages/stream-transform/samples/api.stream.js @@ -1,32 +1,32 @@ - -import { transform } from 'stream-transform'; -import assert from 'node:assert'; +import { transform } from "stream-transform"; +import assert from "node:assert"; const output = []; // Initialize the transformer -const transformer = transform(function(data){ +const transformer = transform(function (data) { data.push(data.shift()); return data; }); // Use the readable stream api to consume transformed records -transformer.on('readable', function(){ - let row; while((row = transformer.read()) !== null){ +transformer.on("readable", function () { + let row; + while ((row = transformer.read()) !== null) { output.push(row); } }); // Catch any error -transformer.on('error', function(err){ +transformer.on("error", function (err) { console.error(err.message); }); // When finished, validate the records with the expected value -transformer.on('finish', function(){ +transformer.on("finish", function () { assert.deepEqual(output, [ - [ '2', '3', '4', '1' ], - [ 'b', 'c', 'd', 'a' ] + ["2", "3", "4", "1"], + ["b", "c", "d", "a"], ]); }); // Write records to the stream -transformer.write(['1','2','3','4']); -transformer.write(['a','b','c','d']); +transformer.write(["1", "2", "3", "4"]); +transformer.write(["a", "b", "c", "d"]); // Close the writable stream transformer.end(); diff --git a/packages/stream-transform/samples/api.sync.js b/packages/stream-transform/samples/api.sync.js index 417bda964..b4c3d349e 100644 --- a/packages/stream-transform/samples/api.sync.js +++ b/packages/stream-transform/samples/api.sync.js @@ -1,16 +1,18 @@ +import { transform } from "stream-transform/sync"; +import assert from "node:assert"; -import { transform } from 'stream-transform/sync'; -import assert from 'node:assert'; - -const records = transform([ - [ 'a', 'b', 'c', 'd' ], - [ '1', '2', '3', '4' ] -], function(record){ - record.push(record.shift()); - return record; -}); +const records = transform( + [ + ["a", "b", "c", "d"], + ["1", "2", "3", "4"], + ], + function (record) { + record.push(record.shift()); + return record; + }, +); assert.deepEqual(records, [ - [ 'b', 'c', 'd', 'a' ], - [ '2', '3', '4', '1' ] + ["b", "c", "d", "a"], + ["2", "3", "4", "1"], ]); diff --git a/packages/stream-transform/samples/mode.callback.js b/packages/stream-transform/samples/mode.callback.js index 9c2472853..e9407668b 100644 --- a/packages/stream-transform/samples/mode.callback.js +++ b/packages/stream-transform/samples/mode.callback.js @@ -1,18 +1,20 @@ +import { transform } from "stream-transform"; -import { transform } from 'stream-transform'; - -transform([ - ['1','2','3','4'], - ['a','b','c','d'] -], function(data, callback){ - setImmediate(function(){ - data.push(data.shift()); - callback(null, data.join(',')+'\n'); - }); -}, { - parallel: 20 -}) - .pipe(process.stdout); +transform( + [ + ["1", "2", "3", "4"], + ["a", "b", "c", "d"], + ], + function (data, callback) { + setImmediate(function () { + data.push(data.shift()); + callback(null, data.join(",") + "\n"); + }); + }, + { + parallel: 20, + }, +).pipe(process.stdout); // Output: // 2,3,4,1 diff --git a/packages/stream-transform/samples/mode.promise.js b/packages/stream-transform/samples/mode.promise.js index d0d4c47a1..efdd31304 100644 --- a/packages/stream-transform/samples/mode.promise.js +++ b/packages/stream-transform/samples/mode.promise.js @@ -15,7 +15,7 @@ transform( }, { parallel: 20, - } + }, ).pipe(process.stdout); // Output: diff --git a/packages/stream-transform/samples/mode.sync.js b/packages/stream-transform/samples/mode.sync.js index 8de45825d..12e942f6d 100644 --- a/packages/stream-transform/samples/mode.sync.js +++ b/packages/stream-transform/samples/mode.sync.js @@ -1,14 +1,15 @@ +import { transform } from "stream-transform"; -import { transform } from 'stream-transform'; - -transform([ - ['1','2','3','4'], - ['a','b','c','d'] -], function(data){ - data.push(data.shift()); - return data.join(',')+'\n'; -}) - .pipe(process.stdout); +transform( + [ + ["1", "2", "3", "4"], + ["a", "b", "c", "d"], + ], + function (data) { + data.push(data.shift()); + return data.join(",") + "\n"; + }, +).pipe(process.stdout); // Output: // 2,3,4,1 diff --git a/packages/stream-transform/samples/option.parallel.sequential.js b/packages/stream-transform/samples/option.parallel.sequential.js index 228592870..49cdd515c 100644 --- a/packages/stream-transform/samples/option.parallel.sequential.js +++ b/packages/stream-transform/samples/option.parallel.sequential.js @@ -1,20 +1,34 @@ - -import { transform } from 'stream-transform'; -import assert from 'node:assert'; +import { transform } from "stream-transform"; +import assert from "node:assert"; // Generate a dataset of 500 records -const records = '.'.repeat(500).split('.').map((_, i) => i); +const records = "." + .repeat(500) + .split(".") + .map((_, i) => i); // Transform the dataset -transform(records, { - parallel: 1 -}, function(record, callback){ - setTimeout(function(){ - callback(null, record); - // Random timeout to prove sequential execution - }, Math.ceil(Math.random() * 10)); -}, function(err, records){ - assert.equal( - records.join(','), - '.'.repeat(500).split('.').map((_, i) => i).join(',') - ); -}); +transform( + records, + { + parallel: 1, + }, + function (record, callback) { + setTimeout( + function () { + callback(null, record); + // Random timeout to prove sequential execution + }, + Math.ceil(Math.random() * 10), + ); + }, + function (err, records) { + assert.equal( + records.join(","), + "." + .repeat(500) + .split(".") + .map((_, i) => i) + .join(","), + ); + }, +); diff --git a/packages/stream-transform/samples/state.handler.js b/packages/stream-transform/samples/state.handler.js index fc52bcb6f..66c630b96 100644 --- a/packages/stream-transform/samples/state.handler.js +++ b/packages/stream-transform/samples/state.handler.js @@ -1,28 +1,21 @@ - -import { transform } from 'stream-transform'; -import assert from 'node:assert'; +import { transform } from "stream-transform"; +import assert from "node:assert"; // Generate a dataset of 5 records -const records = 'record\n'.repeat(5).trim().split('\n'); -const assertions = [ - '2_2_0', - '1_2_1', - '2_4_2', - '1_4_3', - '1_5_4', -]; +const records = "record\n".repeat(5).trim().split("\n"); +const assertions = ["2_2_0", "1_2_1", "2_4_2", "1_4_3", "1_5_4"]; let count = 0; // Execute the transformation -transform(records, {parallel: 2}, function(_, callback){ +transform(records, { parallel: 2 }, function (_, callback) { setTimeout(() => { - const {running, started, finished} = this.state; + const { running, started, finished } = this.state; assert.equal(assertions[count++], `${running}_${started}_${finished}`); callback(null, `${running}_${started}_${finished}\n`); }, 100); }) // Get notify on error - .on('end', function(){ - const {running, started, finished} = this.state; + .on("end", function () { + const { running, started, finished } = this.state; process.stdout.write(`end: ${running}_${started}_${finished}\n`); }) // Print the transformed records to the standard output diff --git a/packages/stream-transform/samples/state.instance.js b/packages/stream-transform/samples/state.instance.js index e120c6bd0..b328b6ba9 100644 --- a/packages/stream-transform/samples/state.instance.js +++ b/packages/stream-transform/samples/state.instance.js @@ -1,19 +1,18 @@ - -import { transform } from 'stream-transform'; +import { transform } from "stream-transform"; // Generate a dataset of 5 records -const records = 'record\n'.repeat(5).trim().split('\n'); +const records = "record\n".repeat(5).trim().split("\n"); // Initialize the transformation const transformer = transform(records, (record, callback) => { setTimeout(() => { - const {running, started, finished} = transformer.state; + const { running, started, finished } = transformer.state; callback(null, `${running}_${started}_${finished}\n`); }, 100); }); // Get notify when done -transformer.on('end', () => { - process.stdout.write('-------\n'); - const {running, started, finished} = transformer.state; +transformer.on("end", () => { + process.stdout.write("-------\n"); + const { running, started, finished } = transformer.state; process.stdout.write(`${running}_${started}_${finished}\n`); }); // Print the transformed records to the standard output