/* CSV Parse 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"; 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, }); // 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) { 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) { this.state.stop = true; } callback(err); } // Implementation of `Transform._flush` _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); }, ); callback(err); } } const parse = function () { let data, options, callback; for (const i in arguments) { const argument = arguments[i]; const type = typeof argument; if ( data === undefined && (typeof argument === "string" || Buffer.isBuffer(argument)) ) { data = argument; } else if (options === undefined && is_object(argument)) { options = argument; } 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 || {}, ); } } const parser = new Parser(options); 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) { records.push(record); } else { records[record[0]] = record[1]; } } }); parser.on("error", function (err) { callback(err, undefined, parser.api.__infoDataSet()); }); parser.on("end", function () { callback(undefined, records, parser.api.__infoDataSet()); }); } if (data !== undefined) { const writer = function () { parser.write(data); parser.end(); }; // Support Deno, Rollup doesnt provide a shim for setImmediate if (typeof setImmediate === "function") { setImmediate(writer); } else { setTimeout(writer, 0); } } return parser; }; // export default parse export { parse, Parser, CsvError };