import { Parser } from './Parser' ; import { Streamer } from './Streamer' ; import { Comma , ForEachCallback , LineBreak , PristineInput , Quote , ReadAllCallback , ReadCallback , Value , } from './types' ; const EOL = '\r\n' ; const SEPARATOR = ',' ; const quoteCharReqex = new RegExp ( '"' , 'g' ) ; const specialCharReqex = new RegExp ( '["\r\n]' , 'g' ) ; const _shouldBeQuoted = ( value , sep ) : boolean => value . search ( specialCharReqex ) >= 0 || value . includes ( sep ) ; const _quoteIfRquired = ( value , sep ) : string => _shouldBeQuoted ( value , sep ) ? '"' + value . replace ( quoteCharReqex , '""' ) + '"' : value ; const _stringifySingleValue = ( item ) : string => { if ( item === 0 ) { item = '0' ; } else if ( item === undefined || item === null ) { item = '' ; } if ( typeof item != 'string' ) { const s = item . toString ( ) ; if ( s == '[object Object]' ) { item = JSON . stringify ( item ) ; if ( item == '{}' ) { item = '' ; } } else { item = s ; } } return item ; } ; const reducer = ( item , memo , sep , prependSep ? ) : Value => { item = _stringifySingleValue ( item ) ; return ( ( memo !== undefined || prependSep ? `${ memo }${ sep }` : '' ) + _quoteIfRquired ( item , sep ) ) ; } ; const detect = ( input ) : Comma => { const separators = [ ',' , ';' , '|' , '\t' ] ; const idx = separators . map ( ( separator ) => input . indexOf ( separator ) ) . reduce ( ( prev , cur ) => prev === - 1 || ( cur !== - 1 && cur < prev ) ? cur : prev ) ; return ( input [ idx ] || ',' ) as Comma ; } ; const stringify = ( input ? , sep = SEPARATOR ) : string => { let ret ; sep = sep || SEPARATOR ; if ( Array . isArray ( input ) ) { if ( input . length === 0 ) { ret = EOL ; } else if ( ! Array . isArray ( input [ 0 ] ) ) { for ( let loop = 0 ; loop < input . length ; loop ++ ) { ret = reducer ( input [ loop ] , ret , sep , loop > 0 ) ; } ret += EOL ; } else if ( Array . isArray ( input [ 0 ] ) ) { ret = input . map ( ( item ) => stringify ( item , sep ) ) . join ( '' ) ; } } else if ( typeof input == 'object' ) { for ( const key in input ) { if ( input . hasOwnProperty ( key ) ) { ret = reducer ( input [ key ] , ret , sep ) ; } } ret += EOL ; } else { ret = reducer ( input , ret , sep ) + EOL ; } return ret as string ; } ; const parse = ( input , sep ? , quo ? ) : Value [ ] [ ] => { if ( sep === undefined ) { sep = detect ( input ) ; } const csv = new Parser ( input , sep , quo ) ; return csv . File ( ) ; } ; function read ( input , callback ) ; function read ( input , sep , callback ) ; function read ( input , sep , quo , callback ) ; function read ( input , sep , quo ? , callback ? ) { if ( callback === undefined ) { if ( quo === undefined ) { if ( typeof sep !== 'function' ) { throw Error ( 'Last/second argument is not a callback' ) ; } callback = sep ; sep = ',' ; } else { if ( typeof quo !== 'function' ) { throw Error ( 'Last/third argument is not a callback' ) ; } callback = quo ; quo = '"' ; } } const csv = new Parser ( input , sep as Comma , quo as Quote ) ; const fields = csv . Row ( ) ; callback ( fields ) ; return csv . pointer ; } function forEach ( input , callback ) ; function forEach ( input , sep , callback ) ; function forEach ( input , sep , quo , callback ) ; function forEach ( input , sep , quo ? , callback ? ) { if ( callback === undefined ) { if ( quo === undefined ) { if ( typeof sep !== 'function' ) { throw Error ( 'Last/second argument is not a callback' ) ; } callback = sep ; sep = ',' ; } else { if ( typeof quo !== 'function' ) { throw Error ( 'Last/third argument is not a callback' ) ; } callback = quo ; quo = '"' ; } } let i = 0 ; let s = 0 ; let r ; while ( ( r = read ( input . slice ( s ) , sep as Comma , quo as Quote , ( fields ) => ( callback as ForEachCallback ) ( fields , i ++ ) ) ) ) { s += r ; } } function readAll ( input , callback ) ; function readAll ( input , sep , callback ) ; function readAll ( input , sep , quo , callback ) ; function readAll ( input , sep , quo ? , callback ? ) { if ( callback === undefined ) { if ( quo === undefined ) { if ( typeof sep !== 'function' ) { throw Error ( 'Last/second argument is not a callback' ) ; } callback = sep ; sep = ',' ; } else { if ( typeof quo !== 'function' ) { throw Error ( 'Last/third argument is not a callback' ) ; } callback = quo ; quo = '"' ; } } const csv = new Parser ( input , sep as Comma , quo as Quote ) ; const rows = csv . File ( ) ; callback ( rows ) ; return csv . pointer ; } function readChunk ( input , callback ) ; function readChunk ( input , sep , callback ) ; function readChunk ( input , sep , quo , callback ) ; function readChunk ( input , sep , quo ? , callback ? ) { if ( callback === undefined ) { if ( quo === undefined ) { if ( typeof sep !== 'function' ) { throw Error ( 'Last/second argument is not a callback' ) ; } callback = sep ; sep = ',' ; } else { if ( typeof quo !== 'function' ) { throw Error ( 'Last/third argument is not a callback' ) ; } callback = quo ; quo = '"' ; } } const csv = new Parser ( input , sep as Comma , quo as Quote ) ; const rows = csv . File ( ) ; let ret = 0 ; if ( csv . pointer < input . length ) { ret = csv . pointer ; } else { rows . pop ( ) ; ret = csv . linePointer ; } callback ( rows ) ; return ret ; } const fetch = ( input , sep ? , quo ? ) : Value [ ] => { let output ; read ( input , sep as Comma , quo as Quote , ( fields ) => { output = fields ; } ) ; return output as Value [ ] ; } ; const createStream = ( options ? ) : Streamer => new Streamer ( options ) ; export { EOL as eol , SEPARATOR as separator , detect , stringify , parse , read , forEach , readAll , readChunk , fetch , createStream , } ;