UNPKG

@luminati-io/luminati-proxy

Version:

A configurable local proxy for luminati.io

270 lines (257 loc) 7.91 kB
// LICENSE_CODE ZON ISC 'use strict'; /*jslint node:true, browser:true*/ (function(){ var define; var is_node = typeof module=='object' && module.exports && module.children; if (!is_node) define = self.define; else define = require('./require_node.js').define(module, '../'); define(['/util/util.js', '/util/array.js'], function(zutil, zarray){ var E = {}; var assign = Object.assign; // Returns an array of arrays: // [['field1', 'field2', 'field3'], ['1','2','3'], [..], ..] E.to_arr = function(data, opt){ opt = assign({field: ',', quote: '"', line: '\n'}, opt); if (opt.cr_as_new_line) data = data.replace(/\r([^\n])/g, '\n$1'); var line = opt.line, field = opt.field, quote = opt.quote; var i = 0, c = data[i], row = 0, array = []; while (c) { while (opt.trim && (c==' ' || c=='\t' || c=='\r')) c = data[++i]; var value = ''; if (c==quote) { // value enclosed by quote c = data[++i]; do { if (c!=quote) { // read a regular character and go to the next character value += c; c = data[++i]; } if (c==quote) { // check for escaped quote if (data[i+1]==quote) { // this is an escaped field. Add a quote // to the value, and move two characters ahead. value += quote; i += 2; c = data[i]; } } } while (c && (c!=quote || data[i+1]==quote)); if (!c) throw 'Unexpected end of data, no closing quote found'; c = data[++i]; } else { // value not escaped with quote while (c && c!=field && c!=line) { value += c; c = data[++i]; } } if (opt.trim) { value = value.trim(); if (c=='\r') c = data[++i]; } // add the value to the array if (array.length<=row) array.push([]); array[row].push(value); // go to the next row or column if (c==field); else if (c==line) row++; else if (c) throw 'Delimiter expected after character '+i; c = data[++i]; } if (i && data[i-1]==field) array[row].push(''); return array; }; // Returns an array of hashs: // [{field1: '1', field2: '2', field3: '3'}, {..}, ..] E.to_obj = function(data, opt){ var arr = E.to_arr(data, opt); if (!arr.length) return arr; var i, result = [], headers = arr[0]; if ((i = headers.indexOf(''))!=-1) throw new Error('Field '+i+' has unknown name'); for (i=1; i<arr.length; i++) { var obj = {}; if (arr[i].length > headers.length) throw new Error('Line '+i+' has more fields than header'); for (var j=0; j<arr[i].length; j++) obj[headers[j]] = arr[i][j]; result.push(obj); } return result; }; function is_complex(v){ return v && typeof v=='object' && (!Array.isArray(v) || v.some(function(e){ return typeof e=='object'; })); } E.escape_field = function(v, opt){ // opt not fully supported if (v==null && opt && opt.null_to_empty) return ''; if (is_complex(v)) v = JSON.stringify(v); else v = ''+v; if (!/["'\n,]/.test(v)) return v; return '"'+v.replace(/"/g, '""')+'"'; }; function flatten(obj, opt, keys){ var key_set = [], k; for (var i = 0; i < keys.length; i++) { k = keys[i]; if (is_complex(obj[k])) { _get_flatenned_keys(obj[k], opt) .forEach(function(h){ key_set.push(k+opt.splitter+h); }); } else key_set.push(k); } return zarray.unique(key_set); } function _get_flatenned_keys(obj, opt, keys){ keys = keys || Object.keys(obj); if (Array.isArray(obj)) { var key_set = []; for (var i = 0; i < obj.length; i++) { if (!zutil.is_object(obj[i])) continue; flatten(obj[i], opt, Object.keys(obj[i])).forEach( function(el){ key_set.push(el); }); } return zarray.unique(key_set).reduce(function(_keys, k){ for (var j = 0; j < obj.length; j++) _keys.push(j+opt.splitter+k); return _keys; }, []); } return flatten(obj, opt, keys); } function get_flatenned_keys(dataset, opt, keys){ var keymap = {}, i; for (i = 0; i<dataset.length; i++) { var _keys = _get_flatenned_keys(dataset[i], opt, keys); for (var j = 0; j<_keys.length; j++) keymap[_keys[j]] = true; } var arr = Object.keys(keymap); // XXX josh/gabriel: this should be grouping same prefix keys, not sorting arr.sort(); // Removes keys where value is considered non-complex due to being an empty // array but, in reality, it is complex in other entries for (i = 0; i < arr.length-1; i++) { var k1 = arr[i], k2 = arr[i+1]; if (!k2.startsWith(k1+opt.splitter)) continue; if (dataset.every(function(d){ var v = get_value(d, k1, opt); return is_complex(v) || Array.isArray(v) && !v.length; })) { arr = arr.filter(function(k){ return k!=k1; }); } } return arr; } function generate_keys(dataset, opt){ var keys; if (!opt.keys) keys = Object.keys(dataset[0]); else if (opt.keys=='auto') { var keymap = {}; for (var i = 0; i<dataset.length; i++) { for (var j = 0, fields = Object.keys(dataset[i]); j<fields.length; j++) { keymap[fields[j]] = true; } } keys = Object.keys(keymap); } else keys = opt.keys; return opt.flatten ? get_flatenned_keys(dataset, opt, keys) : keys; } function get_value(obj, key, opt){ if (obj.hasOwnProperty(key)) return obj[key]; return key.split(opt.splitter).reduce( function(acc, v){ return acc&&acc[v]; }, obj); } E.to_str = function(csv, opt){ var s = '', i, j, a; opt = assign({field: ',', quote: '"', line: '\n', splitter: '$$'}, opt); var line = opt.line, field = opt.field; function line_to_str(vals){ var _s = ''; for (var k=0; k<vals.length; k++) _s += (k ? field : '')+E.escape_field(vals[k], opt); return _s+line; } if (!csv.length && (!opt.keys || opt.keys=='auto')) return ''; if (Array.isArray(csv[0]) && !opt.flatten) { if (opt.keys) s += line_to_str(opt.keys); for (i=0; i<csv.length; i++) s += line_to_str(csv[i]); return s; } var keys = generate_keys(csv, opt); if (opt.print_keys===undefined || opt.print_keys) { s += line_to_str(keys.map(function(k){ var parts = k.split(opt.splitter); return parts.map(function(p){ // indexes start at 1 if (Number.isFinite(+p)) p = +p+1; return p; }).join('_'); })); } for (i=0; i<csv.length; i++) { for (j=0, a=[]; j<keys.length; j++) { var v = get_value(csv[i], keys[j], opt); a.push(v===undefined ? '' : v); } s += line_to_str(a); } return s; }; E.to_blob = function(csv, opt){ return new Blob([E.to_str(csv, opt)], {type: 'application/csv'}); }; return E; }); }());