UNPKG

coffeescript-ui

Version:
283 lines (226 loc) 5.62 kB
class CUI.CSVData extends CUI.Element initOpts: -> super() @addOpts rows: check: (v) -> CUI.util.isArray(v) and v.length > 0 readOpts: -> super() @__max_column_count = 0 if @_rows @rows = @_rows else @rows = [] @giveAllRowsSameNumberOfColumns() return # makes sure, all rows have the same length giveAllRowsSameNumberOfColumns: -> @__max_column_count = 0 for row in @rows col_count = row.length if col_count > @__max_column_count @__max_column_count = col_count for row in @rows if row.length < @__max_column_count for idx in [row.length...@__max_column_count] row[idx] = "" return getMaxColumnCount: -> @__max_column_count getRows: -> @rows getRow: (row_i) -> @rows[row_i] getRowsCount: -> @rows.length debug: -> console.debug "rows:", @rows toText: (_opts={}) -> opts = CUI.Element.readOpts _opts, "CSVData.toText", delimiter: mandatory: true default: ";" check: (v) => CUI.util.isString(v) and v.length > 0 quotechar: mandatory: true default: '"' check: (v) => CUI.util.isString(v) and v.length > 0 always_quote: mandatory: true default: true check: Boolean equal_columns: mandatory: true default: true check: Boolean newline: mandatory: true default: String.fromCharCode(10) check: (v) => CUI.util.isString(v) and v.length > 0 if opts.equal_columns @giveAllRowsSameNumberOfColumns() nl = String.fromCharCode(10) cr = String.fromCharCode(13) _rows = [] for row in @rows _row = [] for col, idx in row if idx > 0 _row.push(opts.delimiter) if CUI.util.isEmpty(col) str = "" else str = ""+col if opts.always_quote quote = true else if str.indexOf(opts.delimiter) > -1 quote = true else if str.indexOf(opts.quotechar) > -1 quote = true else if str.indexOf(nl) > -1 quote = true else if str.indexOf(cr) > -1 quote = true else quote = false if quote _row.push(CUI.CSVData.quote(str, opts.quotechar)) else _row.push(str) _rows.push(_row.join("")) _rows.join(opts.newline) # parse csv info array parse: (_opts={}) -> opts = CUI.Element.readOpts _opts, "CSVData.parse", text: mandatory: true check: String delimiter: check: String quotechar: check: String defer: mandatory: true default: true check: Boolean @rows = [] text = opts.text columns = [] column_idx = 0 column_chars = [] len = text.length idx = 0 in_quotes = false lines = 0 space_chars = [' '] auto_quotechars = ['"',"'"] auto_delimiters = [",",";","\t"] # space_chars = [" "] if opts.delimiter != undefined delimiter = opts.delimiter else delimiter = null if opts.quotechar != undefined quotechar = opts.quotechar else quotechar = null # console.info("CUI.CSV.parse:", len, "chars. delimiter:", delimiter or "detect", "quotechar:", quotechar or "detect") if opts.defer dfr = new CUI.Deferred() do_work = => end_column = => columns[column_idx] = column_chars.join("") column_chars.splice(0) column_idx = column_idx + 1 return end_row = => if columns.length > 0 lines = lines + 1 @rows.push(columns) columns = [] column_idx = 0 return while (idx < len) char = text.charAt(idx) # console.debug "char:", idx, char, text.charCodeAt(idx) if column_chars.length == 0 and not in_quotes and char in space_chars # ignore spaces outside quotes at the beginning of a column idx = idx + 1 continue if quotechar == null and char in auto_quotechars quotechar = char # console.info("CSVData.parse: detected quotechar:", quotechar) if delimiter == null and char in auto_delimiters delimiter = char # console.info("CSVData.parse: detected delimiter:", delimiter) if char == quotechar and (column_chars.length == 0 or in_quotes) if in_quotes if text[idx+1] == quotechar column_chars.push(char) idx = idx + 2 continue else # end quote in_quotes = false idx = idx + 1 continue else in_quotes = true idx = idx + 1 continue if char == delimiter if in_quotes column_chars.push(char) idx = idx + 1 continue else end_column() idx = idx + 1 continue charCode = text.charCodeAt(idx) nextCharCode = text.charCodeAt(idx+1) # do we have a line ending if charCode == 13 or charCode == 10 if (charCode == 13 and nextCharCode == 10) idx = idx + 2 else idx = idx + 1 if in_quotes column_chars.push(String.fromCharCode(10)) else end_column() end_row() if lines%1000==0 and opts.defer dfr.notify(row_count: lines, file_read_idx: idx, file_length: len) CUI.setTimeout ms: 10 call: do_work return continue column_chars.push(char) idx = idx + 1 if column_chars.length > 0 end_column() if columns.length > 0 end_row() @giveAllRowsSameNumberOfColumns() info = row_count: lines, file_length: len, rows: @rows if opts.defer dfr.resolve(info) else return info if opts.defer CUI.setTimeout ms: 0 call: do_work dfr.done => ; # @debug() return dfr.promise() else return do_work() @quote: (str, quotechar = '"') -> quotechar+str.replace(new RegExp(CUI.util.escapeRegExp(quotechar), "g"), quotechar+quotechar)+quotechar