kepler.gl.geoiq
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
720 lines (613 loc) • 70.6 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Processors = exports.PARSE_FIELD_VALUE_FROM_STRING = exports.ACCEPTED_ANALYZER_TYPES = void 0;
exports.analyzerTypeToFieldType = analyzerTypeToFieldType;
exports.formatCsv = formatCsv;
exports.getFieldsFromData = getFieldsFromData;
exports.getSampleForTypeAnalyze = getSampleForTypeAnalyze;
exports.parseCsvRowsByFieldType = parseCsvRowsByFieldType;
exports.parseRowsByFields = parseRowsByFields;
exports.processCsvData = processCsvData;
exports.processGeobuf = processGeobuf;
exports.processGeojson = processGeojson;
exports.processKeplerglJSON = processKeplerglJSON;
exports.processRowObject = processRowObject;
exports.renameDuplicateFields = renameDuplicateFields;
exports.validateInputData = validateInputData;
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _d3Dsv = require("d3-dsv");
var _d3Array = require("d3-array");
var _window = require("global/window");
var _assert = _interopRequireDefault(require("assert"));
var _typeAnalyzer = require("type-analyzer");
var _geojsonNormalize = _interopRequireDefault(require("@mapbox/geojson-normalize"));
var _defaultSettings = require("../constants/default-settings");
var _dataUtils = require("../utils/data-utils");
var _schemas = _interopRequireDefault(require("../schemas"));
var _userGuides = require("../constants/user-guides");
var _utils = require("../utils/utils");
var _PARSE_FIELD_VALUE_FR;
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var ACCEPTED_ANALYZER_TYPES = exports.ACCEPTED_ANALYZER_TYPES = [_typeAnalyzer.DATA_TYPES.DATE, _typeAnalyzer.DATA_TYPES.TIME, _typeAnalyzer.DATA_TYPES.DATETIME, _typeAnalyzer.DATA_TYPES.NUMBER, _typeAnalyzer.DATA_TYPES.INT, _typeAnalyzer.DATA_TYPES.FLOAT, _typeAnalyzer.DATA_TYPES.BOOLEAN, _typeAnalyzer.DATA_TYPES.STRING, _typeAnalyzer.DATA_TYPES.GEOMETRY, _typeAnalyzer.DATA_TYPES.GEOMETRY_FROM_STRING, _typeAnalyzer.DATA_TYPES.PAIR_GEOMETRY_FROM_STRING, _typeAnalyzer.DATA_TYPES.ZIPCODE, _typeAnalyzer.DATA_TYPES.ARRAY, _typeAnalyzer.DATA_TYPES.OBJECT]; // if any of these value occurs in csv, parse it to null;
var CSV_NULLS = ['', 'null', 'NULL', 'Null', 'NaN', 'N'];
var IGNORE_DATA_TYPES = Object.keys(_typeAnalyzer.DATA_TYPES).filter(function (type) {
return !ACCEPTED_ANALYZER_TYPES.includes(type);
});
var PARSE_FIELD_VALUE_FROM_STRING = exports.PARSE_FIELD_VALUE_FROM_STRING = (_PARSE_FIELD_VALUE_FR = {}, (0, _defineProperty2["default"])(_PARSE_FIELD_VALUE_FR, _defaultSettings.ALL_FIELD_TYPES["boolean"], {
valid: function valid(d) {
return typeof d === 'boolean';
},
parse: function parse(d) {
return d === 'true' || d === 'True' || d === '1';
}
}), (0, _defineProperty2["default"])(_PARSE_FIELD_VALUE_FR, _defaultSettings.ALL_FIELD_TYPES.integer, {
valid: function valid(d) {
return parseInt(d, 10) === d;
},
parse: function parse(d) {
return parseInt(d, 10);
}
}), (0, _defineProperty2["default"])(_PARSE_FIELD_VALUE_FR, _defaultSettings.ALL_FIELD_TYPES.timestamp, {
valid: function valid(d, field) {
return ['x', 'X'].includes(field.format) ? typeof d === 'number' : typeof d === 'string';
},
parse: function parse(d, field) {
return ['x', 'X'].includes(field.format) ? Number(d) : d;
}
}), (0, _defineProperty2["default"])(_PARSE_FIELD_VALUE_FR, _defaultSettings.ALL_FIELD_TYPES.real, {
valid: function valid(d) {
return parseFloat(d) === d;
},
parse: parseFloat
}), _PARSE_FIELD_VALUE_FR);
/**
* Process csv data, output a data object with `{fields: [], rows: []}`.
* The data object can be wrapped in a `dataset` and pass to [`addDataToMap`](../actions/actions.md#adddatatomap)
* @param {string} rawData raw csv string
* @returns {Object} data object `{fields: [], rows: []}`
* @public
* @example
* import {processCsvData} from 'kepler.gl/processors';
*
* const testData = `gps_data.utc_timestamp,gps_data.lat,gps_data.lng,gps_data.types,epoch,has_result,id,time,begintrip_ts_utc,begintrip_ts_local,date
* 2016-09-17 00:09:55,29.9900937,31.2590542,driver_analytics,1472688000000,False,1,2016-09-23T00:00:00.000Z,2016-10-01 09:41:39+00:00,2016-10-01 09:41:39+00:00,2016-09-23
* 2016-09-17 00:10:56,29.9927699,31.2461142,driver_analytics,1472688000000,False,2,2016-09-23T00:00:00.000Z,2016-10-01 09:46:37+00:00,2016-10-01 16:46:37+00:00,2016-09-23
* 2016-09-17 00:11:56,29.9907261,31.2312742,driver_analytics,1472688000000,False,3,2016-09-23T00:00:00.000Z,,,2016-09-23
* 2016-09-17 00:12:58,29.9870074,31.2175827,driver_analytics,1472688000000,False,4,2016-09-23T00:00:00.000Z,,,2016-09-23`
*
* const dataset = {
* info: {id: 'test_data', label: 'My Csv'},
* data: processCsvData(testData)
* };
*
* dispatch(addDataToMap({
* datasets: [dataset],
* options: {centerMap: true, readOnly: true}
* }));
*/
function processCsvData(rawData) {
// here we assume the csv file that people uploaded will have first row
// as name of the column
// TODO: add a alert at upload csv to remind define first row
var result = (0, _d3Dsv.csvParseRows)(rawData);
if (!Array.isArray(result) || result.length < 2) {
// looks like an empty file, throw error to be catch
throw new Error('Read File Failed: CSV is empty');
}
var _result = (0, _toArray2["default"])(result),
headerRow = _result[0],
rows = _result.slice(1);
cleanUpFalsyCsvValue(rows); // No need to run type detection on every data point
// here we get a list of none null values to run analyze on
var sample = getSampleForTypeAnalyze({
fields: headerRow,
allData: rows
});
var fields = getFieldsFromData(sample, headerRow);
var parsedRows = parseRowsByFields(rows, fields);
return {
fields: fields,
rows: parsedRows
};
}
/**
* Parse rows of csv by analyzed field types. So that `'1'` -> `1`, `'True'` -> `true`
* @param {Array<Array>} rows
* @param {Array<Object} fields
*/
function parseRowsByFields(rows, fields) {
// Edit rows in place
var geojsonFieldIdx = fields.findIndex(function (f) {
return f.name === '_geojson';
});
fields.forEach(parseCsvRowsByFieldType.bind(null, rows, geojsonFieldIdx));
return rows;
}
/**
* Getting sample data for analyzing field type.
*
* @param {Array<string>} fields an array of field names
* @param {Array<Array>} allData
* @param {Array} sampleCount
* @returns {Array} formatted fields
*/
function getSampleForTypeAnalyze(_ref) {
var fields = _ref.fields,
allData = _ref.allData,
_ref$sampleCount = _ref.sampleCount,
sampleCount = _ref$sampleCount === void 0 ? 50 : _ref$sampleCount;
var total = Math.min(sampleCount, allData.length); // const fieldOrder = fields.map(f => f.name);
var sample = (0, _d3Array.range)(0, total, 1).map(function (d) {
return {};
}); // collect sample data for each field
fields.forEach(function (field, fieldIdx) {
// data counter
var i = 0; // sample counter
var j = 0;
while (j < total) {
if (i >= allData.length) {
// if depleted data pool
sample[j][field] = null;
j++;
} else if ((0, _dataUtils.notNullorUndefined)(allData[i][fieldIdx])) {
sample[j][field] = allData[i][fieldIdx];
j++;
i++;
} else {
i++;
}
}
});
return sample;
}
/**
* Convert falsy value in csv including `'', 'null', 'NULL', 'Null', 'NaN'` to `null`,
* so that type-analyzer won't detect it as string
*
* @param {Array<Array>} rows
*/
function cleanUpFalsyCsvValue(rows) {
for (var i = 0; i < rows.length; i++) {
for (var j = 0; j < rows[i].length; j++) {
// analyzer will set any fields to 'string' if there are empty values
// which will be parsed as '' by d3.csv
// here we parse empty data as null
// TODO: create warning when deltect `CSV_NULLS` in the data
if (!rows[i][j] || CSV_NULLS.includes(rows[i][j])) {
rows[i][j] = null;
}
}
}
}
/**
* Process uploaded csv file to parse value by field type
*
* @param {Array<Array>} rows
* @param geoFieldIdx geo field index
* @param {Object} field
* @param {Number} i
* @returns {void}
*/
function parseCsvRowsByFieldType(rows, geoFieldIdx, field, i) {
var parser = PARSE_FIELD_VALUE_FROM_STRING[field.type];
if (parser) {
// check first not null value of it's already parsed
var first = rows.find(function (r) {
return (0, _dataUtils.notNullorUndefined)(r[i]);
});
if (!first || parser.valid(first[i], field)) {
return;
}
rows.forEach(function (row) {
// parse string value based on field type
if (row[i] !== null) {
row[i] = parser.parse(row[i], field);
if (geoFieldIdx > -1 && row[geoFieldIdx] && row[geoFieldIdx].properties) {
row[geoFieldIdx].properties[field.name] = row[i];
}
}
});
}
}
/**
* Analyze field types from data in `string` format, e.g. uploaded csv.
* Assign `type`, `tableFieldIndex` and `format` (timestamp only) to each field
*
* @param {Array<Object>} data array of row object
* @param {Array} fieldOrder array of field names as string
* @returns {Array<Object>} formatted fields
* @public
* @example
*
* import {getFieldsFromData} from 'kepler.gl/processors';
* const data = [{
* time: '2016-09-17 00:09:55',
* value: '4',
* surge: '1.2',
* isTrip: 'true',
* zeroOnes: '0'
* }, {
* time: '2016-09-17 00:30:08',
* value: '3',
* surge: null,
* isTrip: 'false',
* zeroOnes: '1'
* }, {
* time: null,
* value: '2',
* surge: '1.3',
* isTrip: null,
* zeroOnes: '1'
* }];
*
* const fieldOrder = ['time', 'value', 'surge', 'isTrip', 'zeroOnes'];
* const fields = getFieldsFromData(data, fieldOrder);
* // fields = [
* // {name: 'time', format: 'YYYY-M-D H:m:s', tableFieldIndex: 1, type: 'timestamp'},
* // {name: 'value', format: '', tableFieldIndex: 4, type: 'integer'},
* // {name: 'surge', format: '', tableFieldIndex: 5, type: 'real'},
* // {name: 'isTrip', format: '', tableFieldIndex: 6, type: 'boolean'},
* // {name: 'zeroOnes', format: '', tableFieldIndex: 7, type: 'integer'}];
*
*/
function getFieldsFromData(data, fieldOrder) {
// add a check for epoch timestamp
var metadata = _typeAnalyzer.Analyzer.computeColMeta(data, [{
regex: /.*geojson|all_points/g,
dataType: 'GEOMETRY'
}], {
ignoredDataTypes: IGNORE_DATA_TYPES
});
var _renameDuplicateField = renameDuplicateFields(fieldOrder),
fieldByIndex = _renameDuplicateField.fieldByIndex;
var result = fieldOrder.reduce(function (orderedArray, field, index) {
var name = fieldByIndex[index];
var fieldMeta = metadata.find(function (m) {
return m.key === field;
});
var _ref2 = fieldMeta || {},
type = _ref2.type,
format = _ref2.format;
orderedArray[index] = {
name: name,
format: format,
tableFieldIndex: index + 1,
type: analyzerTypeToFieldType(type)
};
return orderedArray;
}, []);
return result;
}
/**
* pass in an array of field names, rename duplicated one
* and return a map from old field index to new name
*
* @param {Array} fieldOrder
* @returns {Object} new field name by index
*/
function renameDuplicateFields(fieldOrder) {
return fieldOrder.reduce(function (accu, field, i) {
var allNames = accu.allNames;
var fieldName = field; // add a counter to duplicated names
if (allNames.includes(field)) {
var counter = 0;
while (allNames.includes("".concat(field, "-").concat(counter))) {
counter++;
}
fieldName = "".concat(field, "-").concat(counter);
}
accu.fieldByIndex[i] = fieldName;
accu.allNames.push(fieldName);
return accu;
}, {
allNames: [],
fieldByIndex: {}
});
}
/**
* Convert type-analyzer output to kepler.gl field types
*
* @param {string} aType
* @returns {string} corresponding type in `ALL_FIELD_TYPES`
*/
/* eslint-disable complexity */
function analyzerTypeToFieldType(aType) {
var DATE = _typeAnalyzer.DATA_TYPES.DATE,
TIME = _typeAnalyzer.DATA_TYPES.TIME,
DATETIME = _typeAnalyzer.DATA_TYPES.DATETIME,
NUMBER = _typeAnalyzer.DATA_TYPES.NUMBER,
INT = _typeAnalyzer.DATA_TYPES.INT,
FLOAT = _typeAnalyzer.DATA_TYPES.FLOAT,
BOOLEAN = _typeAnalyzer.DATA_TYPES.BOOLEAN,
STRING = _typeAnalyzer.DATA_TYPES.STRING,
GEOMETRY = _typeAnalyzer.DATA_TYPES.GEOMETRY,
GEOMETRY_FROM_STRING = _typeAnalyzer.DATA_TYPES.GEOMETRY_FROM_STRING,
PAIR_GEOMETRY_FROM_STRING = _typeAnalyzer.DATA_TYPES.PAIR_GEOMETRY_FROM_STRING,
ZIPCODE = _typeAnalyzer.DATA_TYPES.ZIPCODE,
ARRAY = _typeAnalyzer.DATA_TYPES.ARRAY,
OBJECT = _typeAnalyzer.DATA_TYPES.OBJECT; // TODO: un recognized types
// CURRENCY PERCENT NONE
switch (aType) {
case DATE:
return _defaultSettings.ALL_FIELD_TYPES.date;
case TIME:
return _defaultSettings.ALL_FIELD_TYPES.string;
case DATETIME:
return _defaultSettings.ALL_FIELD_TYPES.timestamp;
case NUMBER:
case FLOAT:
return _defaultSettings.ALL_FIELD_TYPES.real;
case INT:
return _defaultSettings.ALL_FIELD_TYPES.integer;
case BOOLEAN:
return _defaultSettings.ALL_FIELD_TYPES["boolean"];
case GEOMETRY:
case GEOMETRY_FROM_STRING:
case PAIR_GEOMETRY_FROM_STRING:
case ARRAY:
case OBJECT:
// TODO: create a new data type for objects and arrays
return _defaultSettings.ALL_FIELD_TYPES.geojson;
case STRING:
case ZIPCODE:
return _defaultSettings.ALL_FIELD_TYPES.string;
default:
_window.console.warn("Unsupported analyzer type: ".concat(aType));
return _defaultSettings.ALL_FIELD_TYPES.string;
}
}
/* eslint-enable complexity */
/**
* Process data where each row is an object, output can be passed to [`addDataToMap`](../actions/actions.md#adddatatomap)
* @param {Array<Object>} rawData an array of row object, each object should have the same number of keys
* @returns {Object} dataset containing `fields` and `rows`
* @public
* @example
* import {addDataToMap} from 'kepler.gl/actions';
* import {processRowObject} from 'kepler.gl/processors';
*
* const data = [
* {lat: 31.27, lng: 127.56, value: 3},
* {lat: 31.22, lng: 126.26, value: 1}
* ];
*
* dispatch(addDataToMap({
* datasets: {
* info: {label: 'My Data', id: 'my_data'},
* data: processRowObject(data)
* }
* }));
*/
function processRowObject(rawData) {
if (!Array.isArray(rawData) || !rawData.length) {
return null;
}
var keys = Object.keys(rawData[0]);
var rows = rawData.map(function (d) {
return keys.map(function (key) {
return d[key];
});
}); // pick samples
var sampleData = (0, _dataUtils.getSampleData)(rawData, 500);
var fields = getFieldsFromData(sampleData, keys);
var parsedRows = parseRowsByFields(rows, fields);
return {
fields: fields,
rows: parsedRows
};
}
/**
* Process GeoJSON [`FeatureCollection`](http://wiki.geojson.org/GeoJSON_draft_version_6#FeatureCollection),
* output a data object with `{fields: [], rows: []}`.
* The data object can be wrapped in a `dataset` and pass to [`addDataToMap`](../actions/actions.md#adddatatomap)
*
* @param {Object} rawData raw geojson feature collection
* @returns {Object} dataset containing `fields` and `rows`
* @public
* @example
* import {addDataToMap} from 'kepler.gl/actions';
* import {processGeojson} from 'kepler.gl/processors';
*
* const geojson = {
* "type" : "FeatureCollection",
* "features" : [{
* "type" : "Feature",
* "properties" : {
* "capacity" : "10",
* "type" : "U-Rack"
* },
* "geometry" : {
* "type" : "Point",
* "coordinates" : [ -71.073283, 42.417500 ]
* }
* }]
* };
*
* dispatch(addDataToMap({
* datasets: {
* info: {
* label: 'Sample Taxi Trips in New York City',
* id: 'test_trip_data'
* },
* data: processGeojson(geojson)
* }
* }));
*/
function processGeojson(rawData) {
var geojson = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var normalizedGeojson = (0, _geojsonNormalize["default"])(rawData);
if (!normalizedGeojson || !Array.isArray(normalizedGeojson.features)) {
var error = new Error("Read File Failed: File is not a valid GeoJSON. Read more about [supported file format](".concat(_userGuides.GUIDES_FILE_FORMAT, ")"));
throw error; // fail to normalize geojson
} // getting all feature fields
var allData = normalizedGeojson.features.reduce(function (accu, f, i) {
if (f.geometry) {
geojson ? accu.push(_objectSpread({
// add feature to _geojson field
_geojson: f
}, f.properties || {})) : accu.push(_objectSpread({}, f.properties || {}));
}
return accu;
}, []); // get all the field
var fields = allData.reduce(function (prev, curr) {
Object.keys(curr).forEach(function (key) {
if (!prev.includes(key)) {
prev.push(key);
}
});
return prev;
}, []); // make sure each feature has exact same fields
allData.forEach(function (d) {
fields.forEach(function (f) {
if (!(f in d)) {
d[f] = null;
}
});
});
var processRow = processRowObject(allData);
return processRow;
}
/**
* On export data to csv
* @param {Array<Array>} data `dataset.allData` or filtered data `dataset.data`
* @param {Array<Object>} fields `dataset.fields`
* @returns {string} csv string
*/
function formatCsv(data, fields) {
var columns = fields.map(function (f) {
return f.name;
});
var formattedData = [columns]; // parse geojson object as string
data.forEach(function (row) {
formattedData.push(row.map(function (d, i) {
return (0, _dataUtils.parseFieldValue)(d, fields[i].type);
}));
});
return (0, _d3Dsv.csvFormatRows)(formattedData);
}
/**
* Validate input data, adding missing field types, rename duplicate columns
* @param {Object} data dataset.data
* @param {Array<Object>} data.fields an array of fields
* @param {Array<Object>} data.rows an array of data rows
* @returns {{allData: Array, fields: Array}}
*/
function validateInputData(data) {
if (!(0, _utils.isPlainObject)(data)) {
(0, _assert["default"])('addDataToMap Error: dataset.data cannot be null');
return null;
} else if (!Array.isArray(data.fields)) {
(0, _assert["default"])('addDataToMap Error: expect dataset.data.fields to be an array');
return null;
} else if (!Array.isArray(data.rows)) {
(0, _assert["default"])('addDataToMap Error: expect dataset.data.rows to be an array');
return null;
}
var fields = data.fields,
rows = data.rows; // check if all fields has name, format and type
var allValid = fields.every(function (f, i) {
if (!(0, _utils.isPlainObject)(f)) {
(0, _assert["default"])("fields needs to be an array of object, but find ".concat((0, _typeof2["default"])(f)));
fields[i] = {};
}
if (!f.name) {
(0, _assert["default"])("field.name is required but missing in ".concat(JSON.stringify(f))); // assign a name
fields[i].name = "column_".concat(i);
}
if (!_defaultSettings.ALL_FIELD_TYPES[f.type]) {
(0, _assert["default"])("unknown field type ".concat(f.type));
return false;
} // check time format is correct based on first 10 not empty element
if (f.type === _defaultSettings.ALL_FIELD_TYPES.timestamp) {
var sample = findNonEmptyRowsAtField(rows, i, 10).map(function (r) {
return {
ts: r[i]
};
});
var analyzedType = _typeAnalyzer.Analyzer.computeColMeta(sample)[0];
return analyzedType.category === 'TIME' && analyzedType.format === f.format;
}
return true;
});
if (allValid) {
return {
rows: rows,
fields: fields
};
} // if any field has missing type, recalculate it for everyone
// because we simply lost faith in humanity
var sampleData = getSampleForTypeAnalyze({
fields: fields.map(function (f) {
return f.name;
}),
allData: rows
});
var fieldOrder = fields.map(function (f) {
return f.name;
});
var meta = getFieldsFromData(sampleData, fieldOrder);
var updatedFields = fields.map(function (f, i) {
return _objectSpread(_objectSpread({}, f), {}, {
type: meta[i].type,
format: meta[i].format
});
});
return {
fields: updatedFields,
rows: rows
};
}
function findNonEmptyRowsAtField(rows, fieldIdx, total) {
var sample = [];
var i = 0;
while (sample.length < total && i < rows.length) {
if ((0, _dataUtils.notNullorUndefined)(rows[i][fieldIdx])) {
sample.push(rows[i]);
}
i++;
}
return sample;
}
/**
* Process saved kepler.gl json to be pass to [`addDataToMap`](../actions/actions.md#adddatatomap).
* The json object should contain `datasets` and `config`.
* @param {Object} rawData
* @param {Array} rawData.datasets
* @param {Object} rawData.config
* @returns {Object} datasets and config `{datasets: {}, config: {}}`
* @public
* @example
* import {addDataToMap} from 'kepler.gl/actions';
* import {processKeplerglJSON} from 'kepler.gl/processors';
*
* dispatch(addDataToMap(processKeplerglJSON(keplerGlJson)));
*/
function processKeplerglJSON(rawData) {
return rawData ? _schemas["default"].load(rawData.datasets, rawData.config) : null;
}
/**
* @param buffer geobuf: a binary encoding for geographic data
* https://github.com/mapbox/geobuf
*/
function processGeobuf(bufferStr) {
var buffer = new Uint8Array(bufferStr);
var geojson = geobuf.decode(new Pbf(buffer));
return processGeojson(geojson);
}
var Processors = exports.Processors = {
processGeojson: processGeojson,
processCsvData: processCsvData,
processRowObject: processRowObject,
processKeplerglJSON: processKeplerglJSON,
analyzerTypeToFieldType: analyzerTypeToFieldType,
getFieldsFromData: getFieldsFromData,
parseCsvRowsByFieldType: parseCsvRowsByFieldType,
formatCsv: formatCsv
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcm9jZXNzb3JzL2RhdGEtcHJvY2Vzc29yLmpzIl0sIm5hbWVzIjpbIkFDQ0VQVEVEX0FOQUxZWkVSX1RZUEVTIiwiQW5hbHl6ZXJEQVRBX1RZUEVTIiwiREFURSIsIlRJTUUiLCJEQVRFVElNRSIsIk5VTUJFUiIsIklOVCIsIkZMT0FUIiwiQk9PTEVBTiIsIlNUUklORyIsIkdFT01FVFJZIiwiR0VPTUVUUllfRlJPTV9TVFJJTkciLCJQQUlSX0dFT01FVFJZX0ZST01fU1RSSU5HIiwiWklQQ09ERSIsIkFSUkFZIiwiT0JKRUNUIiwiQ1NWX05VTExTIiwiSUdOT1JFX0RBVEFfVFlQRVMiLCJPYmplY3QiLCJrZXlzIiwiZmlsdGVyIiwidHlwZSIsImluY2x1ZGVzIiwiUEFSU0VfRklFTERfVkFMVUVfRlJPTV9TVFJJTkciLCJBTExfRklFTERfVFlQRVMiLCJ2YWxpZCIsImQiLCJwYXJzZSIsImludGVnZXIiLCJwYXJzZUludCIsInRpbWVzdGFtcCIsImZpZWxkIiwiZm9ybWF0IiwiTnVtYmVyIiwicmVhbCIsInBhcnNlRmxvYXQiLCJwcm9jZXNzQ3N2RGF0YSIsInJhd0RhdGEiLCJyZXN1bHQiLCJBcnJheSIsImlzQXJyYXkiLCJsZW5ndGgiLCJFcnJvciIsImhlYWRlclJvdyIsInJvd3MiLCJjbGVhblVwRmFsc3lDc3ZWYWx1ZSIsInNhbXBsZSIsImdldFNhbXBsZUZvclR5cGVBbmFseXplIiwiZmllbGRzIiwiYWxsRGF0YSIsImdldEZpZWxkc0Zyb21EYXRhIiwicGFyc2VkUm93cyIsInBhcnNlUm93c0J5RmllbGRzIiwiZ2VvanNvbkZpZWxkSWR4IiwiZmluZEluZGV4IiwiZiIsIm5hbWUiLCJmb3JFYWNoIiwicGFyc2VDc3ZSb3dzQnlGaWVsZFR5cGUiLCJiaW5kIiwic2FtcGxlQ291bnQiLCJ0b3RhbCIsIk1hdGgiLCJtaW4iLCJtYXAiLCJmaWVsZElkeCIsImkiLCJqIiwiZ2VvRmllbGRJZHgiLCJwYXJzZXIiLCJmaXJzdCIsImZpbmQiLCJyIiwicm93IiwicHJvcGVydGllcyIsImRhdGEiLCJmaWVsZE9yZGVyIiwibWV0YWRhdGEiLCJBbmFseXplciIsImNvbXB1dGVDb2xNZXRhIiwicmVnZXgiLCJkYXRhVHlwZSIsImlnbm9yZWREYXRhVHlwZXMiLCJyZW5hbWVEdXBsaWNhdGVGaWVsZHMiLCJmaWVsZEJ5SW5kZXgiLCJyZWR1Y2UiLCJvcmRlcmVkQXJyYXkiLCJpbmRleCIsImZpZWxkTWV0YSIsIm0iLCJrZXkiLCJ0YWJsZUZpZWxkSW5kZXgiLCJhbmFseXplclR5cGVUb0ZpZWxkVHlwZSIsImFjY3UiLCJhbGxOYW1lcyIsImZpZWxkTmFtZSIsImNvdW50ZXIiLCJwdXNoIiwiYVR5cGUiLCJkYXRlIiwic3RyaW5nIiwiZ2VvanNvbiIsImdsb2JhbENvbnNvbGUiLCJ3YXJuIiwicHJvY2Vzc1Jvd09iamVjdCIsInNhbXBsZURhdGEiLCJwcm9jZXNzR2VvanNvbiIsIm5vcm1hbGl6ZWRHZW9qc29uIiwiZmVhdHVyZXMiLCJlcnJvciIsIkdVSURFU19GSUxFX0ZPUk1BVCIsImdlb21ldHJ5IiwiX2dlb2pzb24iLCJwcmV2IiwiY3VyciIsInByb2Nlc3NSb3ciLCJmb3JtYXRDc3YiLCJjb2x1bW5zIiwiZm9ybWF0dGVkRGF0YSIsInZhbGlkYXRlSW5wdXREYXRhIiwiYWxsVmFsaWQiLCJldmVyeSIsIkpTT04iLCJzdHJpbmdpZnkiLCJmaW5kTm9uRW1wdHlSb3dzQXRGaWVsZCIsInRzIiwiYW5hbHl6ZWRUeXBlIiwiY2F0ZWdvcnkiLCJtZXRhIiwidXBkYXRlZEZpZWxkcyIsInByb2Nlc3NLZXBsZXJnbEpTT04iLCJLZXBsZXJHbFNjaGVtYSIsImxvYWQiLCJkYXRhc2V0cyIsImNvbmZpZyIsInByb2Nlc3NHZW9idWYiLCJidWZmZXJTdHIiLCJidWZmZXIiLCJVaW50OEFycmF5IiwiZ2VvYnVmIiwiZGVjb2RlIiwiUGJmIiwiUHJvY2Vzc29ycyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQW9CQTs7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Rjs7QUFDRCxTQUFPcEIsTUFBUDtBQUNEO0FBQ0Q7Ozs7Ozs7Ozs7Ozs7Ozs7QUFjTyxTQUFTb0YsbUJBQVQsQ0FBNkI3RixPQUE3QixFQUFzQztBQUMzQyxTQUFPQSxPQUFPLEdBQUc4RixvQkFBZUMsSUFBZixDQUFvQi9GLE9BQU8sQ0FBQ2dHLFFBQTVCLEVBQXNDaEcsT0FBTyxDQUFDaUcsTUFBOUMsQ0FBSCxHQUEyRCxJQUF6RTtBQUNEO0FBRUQ7Ozs7OztBQUlPLFNBQVNDLGFBQVQsQ0FBdUJDLFNBQXZCLEVBQWtDO0FBQ3ZDLE1BQU1DLE1BQU0sR0FBRyxJQUFJQyxVQUFKLENBQWVGLFNBQWYsQ0FBZjtBQUNBLE1BQU1uQyxPQUFPLEdBQUdzQyxNQUFNLENBQUNDLE1BQVAsQ0FBYyxJQUFJQyxHQUFKLENBQVFKLE1BQVIsQ0FBZCxDQUFoQjtBQUNBLFNBQU8vQixjQUFjLENBQUNMLE9BQUQsQ0FBckI7QUFDRDs7QUFFTSxJQUFNeUMsVUFBVSx3QkFBRztBQUN4QnBDLEVBQUFBLGNBQWMsRUFBZEEsY0FEd0I7QUFFeEJ0RSxFQUFBQSxjQUFjLEVBQWRBLGNBRndCO0FBR3hCb0UsRUFBQUEsZ0JBQWdCLEVBQWhCQSxnQkFId0I7QUFJeEIwQixFQUFBQSxtQkFBbUIsRUFBbkJBLG1CQUp3QjtBQUt4QnRDLEVBQUFBLHVCQUF1QixFQUF2QkEsdUJBTHdCO0FBTXhCMUMsRUFBQUEsaUJBQWlCLEVBQWpCQSxpQkFOd0I7QUFPeEJRLEVBQUFBLHVCQUF1QixFQUF2QkEsdUJBUHdCO0FBUXhCMEQsRUFBQUEsU0FBUyxFQUFUQTtBQVJ3QixDQUFuQiIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAoYykgMjAyMyBVYmVyIFRlY2hub2xvZ2llcywgSW5jLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbi8vIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbi8vIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbi8vIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxuLy8gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7Y3N2UGFyc2VSb3dzLCBjc3ZGb3JtYXRSb3dzfSBmcm9tICdkMy1kc3YnO1xuaW1wb3J0IHtyYW5nZX0gZnJvbSAnZDMtYXJyYXknO1xuaW1wb3J0IHtjb25zb2xlIGFzIGdsb2JhbENvbnNvbGV9IGZyb20gJ2dsb2JhbC93aW5kb3cnO1xuaW1wb3J0IGFzc2VydCBmcm9tICdhc3NlcnQnO1xuaW1wb3J0IHtBbmFseXplciwgREFUQV9UWVBFUyBhcyBBbmFseXplckRBVEFfVFlQRVN9IGZyb20gJ3R5cGUtYW5hbHl6ZXInO1xuaW1wb3J0IG5vcm1hbGl6ZSBmcm9tICdAbWFwYm94L2dlb2pzb24tbm9ybWFsaXplJztcbmltcG9ydCB7QUxMX0ZJRUxEX1RZUEVTfSBmcm9tICdjb25zdGFudHMvZGVmYXVsdC1zZXR0aW5ncyc7XG5pbXBvcnQge1xuICBub3ROdWxsb3JVbmRlZmluZWQsXG4gIHBhcnNlRmllbGRWYWx1ZSxcbiAgZ2V0U2FtcGxlRGF0YVxufSBmcm9tICd1dGlscy9kYXRhLXV0aWxzJztcbmltcG9ydCBLZXBsZXJHbFNjaGVtYSBmcm9tICdzY2hlbWFzJztcbmltcG9ydCB7R1VJREVTX0ZJTEVfRk9STUFUfSBmcm9tICdjb25zdGFudHMvdXNlci1ndWlkZXMnO1xuaW1wb3J0IHtpc1BsYWluT2JqZWN0fSBmcm9tICd1dGlscy91dGlscyc7XG5cbmV4cG9ydCBjb25zdCBBQ0NFUFRFRF9BTkFMWVpFUl9UWVBFUyA9IFtcbiAgQW5hbHl6ZXJEQVRBX1RZUEVTLkRBVEUsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5USU1FLFxuICBBbmFseXplckRBVEFfVFlQRVMuREFURVRJTUUsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5OVU1CRVIsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5JTlQsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5GTE9BVCxcbiAgQW5hbHl6ZXJEQVRBX1RZUEVTLkJPT0xFQU4sXG4gIEFuYWx5emVyREFUQV9UWVBFUy5TVFJJTkcsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5HRU9NRVRSWSxcbiAgQW5hbHl6ZXJEQVRBX1RZUEVTLkdFT01FVFJZX0ZST01fU1RSSU5HLFxuICBBbmFseXplckRBVEFfVFlQRVMuUEFJUl9HRU9NRVRSWV9GUk9NX1NUUklORyxcbiAgQW5hbHl6ZXJEQVRBX1RZUEVTLlpJUENPREUsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5BUlJBWSxcbiAgQW5hbHl6ZXJEQVRBX1RZUEVTLk9CSkVDVFxuXTtcblxuLy8gaWYgYW55IG9mIHRoZXNlIHZhbHVlIG9jY3VycyBpbiBjc3YsIHBhcnNlIGl0IHRvIG51bGw7XG5jb25zdCBDU1ZfTlVMTFMgPSBbJycsICdudWxsJywgJ05VTEwnLCAnTnVsbCcsICdOYU4nLCAnTiddO1xuXG5jb25zdCBJR05PUkVfREFUQV9UWVBFUyA9IE9iamVjdC5rZXlzKEFuYWx5emVyREFUQV9UWVBFUykuZmlsdGVyKFxuICB0eXBlID0+ICFBQ0NFUFRFRF9BTkFMWVpFUl9UWVBFUy5pbmNsdWRlcyh0eXBlKVxuKTtcblxuZXhwb3J0IGNvbnN0IFBBUlNFX0ZJRUxEX1ZBTFVFX0ZST01fU1RSSU5HID0ge1xuICBbQUxMX0ZJRUxEX1RZUEVTLmJvb2xlYW5dOiB7XG4gICAgdmFsaWQ6IGQgPT4gdHlwZW9mIGQgPT09ICdib29sZWFuJyxcbiAgICBwYXJzZTogZCA9PiBkID09PSAndHJ1ZScgfHwgZCA9PT0gJ1RydWUnIHx8IGQgPT09ICcxJ1xuICB9LFxuICBbQUxMX0ZJRUxEX1RZUEVTLmludGVnZXJdOiB7XG4gICAgdmFsaWQ6IGQgPT4gcGFyc2VJbnQoZCwgMTApID09PSBkLFxuICAgIHBhcnNlOiBkID0+IHBhcnNlSW50KGQsIDEwKVxuICB9LFxuICBbQUxMX0ZJRUxEX1RZUEVTLnRpbWVzdGFtcF06IHtcbiAgICB2YWxpZDogKGQsIGZpZWxkKSA9PlxuICAgICAgWyd4JywgJ1gnXS5pbmNsdWRlcyhmaWVsZC5mb3JtYXQpXG4gICAgICAgID8gdHlwZW9mIGQgPT09ICdudW1iZXInXG4gICAgICAgIDogdHlwZW9mIGQgPT09ICdzdHJpbmcnLFxuICAgIHBhcnNlOiAoZCwgZmllbGQpID0+IChbJ3gnLCAnWCddLmluY2x1ZGVzKGZpZWxkLmZvcm1hdCkgPyBOdW1iZXIoZCkgOiBkKVxuICB9LFxuICBbQUxMX0ZJRUxEX1RZUEVTLnJlYWxdOiB7XG4gICAgdmFsaWQ6IGQgPT4gcGFyc2VGbG9hdChkKSA9PT0gZCxcbiAgICBwYXJzZTogcGFyc2VGbG9hdFxuICB9XG59O1xuXG4vKipcbiAqIFByb2Nlc3MgY3N2IGRhdGEsIG91dHB1dCBhIGRhdGEgb2JqZWN0IHdpdGggYHtmaWVsZHM6IFtdLCByb3dzOiBbXX1gLlxuICogVGhlIGRhdGEgb2JqZWN0IGNhbiBiZSB3cmFwcGVkIGluIGEgYGRhdGFzZXRgIGFuZCBwYXNzIHRvIFtgYWRkRGF0YVRvTWFwYF0oLi4vYWN0aW9ucy9hY3Rpb25zLm1kI2FkZGRhdGF0b21hcClcbiAqIEBwYXJhbSB7c3RyaW5nfSByYXdEYXRhIHJhdyBjc3Ygc3RyaW5nXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBkYXRhIG9iamVjdCBge2ZpZWxkczogW10sIHJvd3M6IFtdfWBcbiAqIEBwdWJsaWNcbiAqIEBleGFtcGxlXG4gKiBpbXBvcnQge3Byb2Nlc3NDc3ZEYXRhfSBmcm9tICdrZXBsZXIuZ2wvcHJvY2Vzc29ycyc7XG4gKlxuICogY29uc3QgdGVzdERhdGEgPSBgZ3BzX2RhdGEudXRjX3RpbWVzdGFtcCxncHNfZGF0YS5sYXQsZ3BzX2RhdGEubG5nLGdwc19kYXRhLnR5cGVzLGVwb2NoLGhhc19yZXN1bHQsaWQsdGltZSxiZWdpbnRyaXBfdHNfdXRjLGJlZ2ludHJpcF90c19sb2NhbCxkYXRlXG4gKiAyMDE2LTA5LTE3IDAwOjA5OjU1LDI5Ljk5MDA5MzcsMzEuMjU5MDU0Mixkcml2ZXJfYW5hbHl0aWNzLDE0NzI2ODgwMDAwMDAsRmFsc2UsMSwyMDE2LTA5LTIzVDAwOjAwOjAwLjAwMFosMjAxNi0xMC0wMSAwOTo0MTozOSswMDowMCwyMDE2LTEwLTAxIDA5OjQxOjM5KzAwOjAwLDIwMTYtMDktMjNcbiAqIDIwMTYtMDktMTcgMDA6MTA6NTYsMjkuOTkyNzY5OSwzMS4yNDYxMTQyLGRyaXZlcl9hbmFseXRpY3MsMTQ3MjY4ODAwMDAwMCxGYWxzZSwyLDIwMTYtMDktMjNUMDA6MDA6MDAuMDAwWiwyMDE2LTEwLTAxIDA5OjQ2OjM3KzAwOjAwLDIwMTYtMTAtMDEgMTY6NDY6MzcrMDA6MDAsMjAxNi0wOS0yM1xuICogMjAxNi0wOS0xNyAwMDoxMTo1NiwyOS45OTA3MjYxLDMxLjIzMTI3NDIsZHJpdmVyX2FuYWx5dGljcywxNDcyNjg4MDAwMDAwLEZhbHNlLDMsMjAxNi0wOS0yM1QwMDowMDowMC4wMDBaLCwsMjAxNi0wOS0yM1xuICogMjAxNi0wOS0xNyAwMDoxMjo1OCwyOS45ODcwMDc0LDMxLjIxNzU4MjcsZHJpdmVyX2FuYWx5dGljcywxNDcyNjg4MDAwMDAwLEZhbHNlLDQsMjAxNi0wOS0yM1QwMDowMDowMC4wMDBaLCwsMjAxNi0wOS0yM2BcbiAqXG4gKiBjb25zdCBkYXRhc2V0ID0ge1xuICogIGluZm86IHtpZDogJ3Rlc3RfZGF0YScsIGxhYmVsOiAnTXkgQ3N2J30sXG4gKiAgZGF0YTogcHJvY2Vzc0NzdkRhdGEodGVzdERhdGEpXG4gKiB9O1xuICpcbiAqIGRpc3BhdGNoKGFkZERhdGFUb01hcCh7XG4gKiAgZGF0YXNldHM6IFtkYXRhc2V0XSxcbiAqICBvcHRpb25zOiB7Y2VudGVyTWFwOiB0cnVlLCByZWFkT25seTogdHJ1ZX1cbiAqIH0pKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByb2Nlc3NDc3ZEYXRhKHJhd0RhdGEpIHtcbiAgLy8gaGVyZSB3ZSBhc3N1bWUgdGhlIGNzdiBmaWxlIHRoYXQgcGVvcGxlIHVwbG9hZGVkIHdpbGwgaGF2ZSBmaXJzdCByb3dcbiAgLy8gYXMgbmFtZSBvZiB0aGUgY29sdW1uXG4gIC8vIFRPRE86IGFkZCBhIGFsZXJ0IGF0IHVwbG9hZCBjc3YgdG8gcmVtaW5kIGRlZmluZSBmaXJzdCByb3dcbiAgY29uc3QgcmVzdWx0ID0gY3N2UGFyc2VSb3dzKHJhd0RhdGEpO1xuICBpZiAoIUFycmF5LmlzQXJyYXkocmVzdWx0KSB8fCByZXN1bHQubGVuZ3RoIDwgMikge1xuICAgIC8vIGxvb2tzIGxpa2UgYW4gZW1wdHkgZmlsZSwgdGhyb3cgZXJyb3IgdG8gYmUgY2F0Y2hcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1JlYWQgRmlsZSBGYWlsZWQ6IENTViBpcyBlbXB0eScpO1xuICB9XG5cbiAgY29uc3QgW2hlYWRlclJvdywgLi4ucm93c10gPSByZXN1bHQ7XG5cbiAgY2xlYW5VcEZhbHN5Q3N2VmFsdWUocm93cyk7XG4gIC8vIE5vIG5lZWQgdG8gcnVuIHR5cGUgZGV0ZWN0aW9uIG9uIGV2ZXJ5IGRhdGEgcG9pbnRcbiAgLy8gaGVyZS