/* CSV Stringify 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'; class Stringifier extends Transform { constructor(opts = {}){ super({...{writableObjectMode: true}, ...opts}); const [err, options] = normalize_options(opts); if(err !== undefined) throw err; // Expose options this.options = options; // Internal state this.state = { stop: false }; // Information this.info = { records: 0 }; this.api = stringifier(this.options, this.state, this.info); this.api.options.on_record = (...args) => { this.emit('record', ...args); }; } _transform(chunk, encoding, callback){ if(this.state.stop === true){ return; } const err = this.api.__transform(chunk, this.push.bind(this)); if(err !== undefined){ this.state.stop = true; } callback(err); } _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){ this.api.bom(this.push.bind(this)); const err = this.api.headers(this.push.bind(this)); if(err) callback(err); } callback(); } } const stringify = function(){ let data, options, callback; for(const i in arguments){ const argument = arguments[i]; const type = typeof argument; if(data === undefined && (Array.isArray(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}` ]); } } const stringifier = new Stringifier(options); if(callback){ const chunks = []; stringifier.on('readable', function(){ let chunk; while((chunk = this.read()) !== null){ chunks.push(chunk); } }); stringifier.on('error', function(err){ callback(err); }); stringifier.on('end', function(){ try { 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" // See [#386](https://github.com/adaltas/node-csv/pull/386) callback(err); return; } }); } 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'){ setImmediate(writer); }else{ setTimeout(writer, 0); } } return stringifier; }; // export default stringify export { stringify, CsvError, Stringifier };