diff --git a/.flowconfig b/.flowconfig new file mode 100644 index 0000000..f56baed --- /dev/null +++ b/.flowconfig @@ -0,0 +1,13 @@ +[ignore] +/node_modules/es-abstract/.* +/node_modules/has/.* + +[include] + +[libs] + +[lints] + +[options] + +[strict] diff --git a/package-lock.json b/package-lock.json index 18dc1f2..ddd50d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1007,6 +1007,11 @@ "write": "0.2.1" } }, + "flow-bin": { + "version": "0.62.0", + "resolved": "https://unpm.uberinternal.com/flow-bin/-/flow-bin-0.62.0.tgz", + "integrity": "sha1-FLymaabj+VwLwMLR61XsTpjLHYM=" + }, "for-each": { "version": "0.3.2", "resolved": "https://unpm.uberinternal.com/for-each/-/for-each-0.3.2.tgz", diff --git a/package.json b/package.json index 53f0ac5..aff9654 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,9 @@ "lint": "eslint src test", "test": "tape test" }, - "dependencies": {}, + "dependencies": { + "flow-bin": "^0.62.0" + }, "devDependencies": { "eslint": "^4.4.1", "eslint-config-uber-es5": "^2.0.3", diff --git a/src/analyzer.js b/src/analyzer.js index 46f21f5..67ea3df 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -1,3 +1,4 @@ +// @flow // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -20,19 +21,22 @@ 'use strict'; -var CONSTANT = require('./constant'); -var VALIDATOR_MAP = require('./validator-map'); -var Utils = require('./utils'); +import CONSTANT from './constant'; +import VALIDATOR_MAP from './validator-map'; +import { + findFirstNonNullValue, + detectTimeFormat +} from './utils'; -var NUMBER_OF_ALLOWED_HITS = 3; +const NUMBER_OF_ALLOWED_HITS = 3; -var Analyzer = {}; +const Analyzer = {}; -Analyzer._category = function _category(colType) { +function _category(colType) { return CONSTANT.TYPES_TO_CATEGORIES[colType] || CONSTANT.CATEGORIES.DIMENSION; -}; +} -var VALIDATOR_CONSIDERS_EMPTY_STRING_NULL = { +const VALIDATOR_CONSIDERS_EMPTY_STRING_NULL = { PAIR_GEOMETRY_FROM_STRING: true, GEOMETRY_FROM_STRING: true, NUMBER: true @@ -59,14 +63,14 @@ function valueIsNullForValidator(value, validatorName) { function buildValidatorFinder(data, columnName) { return function findTypeFromValidators(validatorName) { // you get three strikes until we dont think you are this type - var nonNullData = data.filter(function iterator(row) { - var value = row[columnName]; + const nonNullData = data.filter(function iterator(row) { + const value = row[columnName]; return !valueIsNullForValidator(value, validatorName); }); - var strikes = Math.min(NUMBER_OF_ALLOWED_HITS, nonNullData.length); - var hits = 0; + const strikes = Math.min(NUMBER_OF_ALLOWED_HITS, nonNullData.length); + const hits = 0; nonNullData.some(function iterateAcrossData(row) { - var value = row[columnName]; + const value = row[columnName]; if (Boolean(VALIDATOR_MAP[validatorName](value)) === false) { strikes -= 1; } else { @@ -102,36 +106,36 @@ function getTypeFromRules(analyzerRules, columnName) { * @param {Object} analyzerRules - regexs describing column overrides * @return {Object} column metadata **/ -Analyzer.computeColMeta = function computeColMeta(data, analyzerRules) { +function computeColMeta(data: Object[], analyzerRules) { if (!data || Object.keys(data).length === 0) { return []; } - var _columns = Object.keys(data[0]); + const _columns = Object.keys(data[0]); /* eslint-disable max-statements */ return _columns.reduce(function iterator(res, columnName) { - var format = ''; + let format = ''; // First try to get the column from the rules - var type = getTypeFromRules(analyzerRules, columnName); + let type = getTypeFromRules(analyzerRules, columnName); // If it's not there then try to infer the type if (!type) { type = CONSTANT.VALIDATORS.find(buildValidatorFinder(data, columnName)); } // if theres still no type, dump this column - var category = Analyzer._category(type); + const category = _category(type); if (!type) { return res; } // if its a time, detect and record the time if (type && CONSTANT.TIME_VALIDATORS.indexOf(type) !== -1) { // Find the first non-null value. - var sample = Utils.findFirstNonNullValue(data, columnName); + const sample = findFirstNonNullValue(data, columnName); if (sample === null) { return res; } - format = Utils.detectTimeFormat(sample, type); + format = detectTimeFormat(sample, type); } - var colMeta = { + const colMeta = { key: columnName, label: columnName, type: type, @@ -140,14 +144,14 @@ Analyzer.computeColMeta = function computeColMeta(data, analyzerRules) { }; if (type === CONSTANT.DATA_TYPES.GEOMETRY) { - var geoSample = Utils.findFirstNonNullValue(data, columnName); + const geoSample = findFirstNonNullValue(data, columnName); if (geoSample === null) { return res; } colMeta.geoType = geoSample.type.toUpperCase(); } if (type === CONSTANT.DATA_TYPES.GEOMETRY_FROM_STRING) { - var geoStringSample = Utils.findFirstNonNullValue(data, columnName); + const geoStringSample = findFirstNonNullValue(data, columnName); if (geoStringSample === null) { return res; } @@ -161,5 +165,3 @@ Analyzer.computeColMeta = function computeColMeta(data, analyzerRules) { }, []); }; /* eslint-enable max-statements */ - -module.exports = Analyzer; diff --git a/src/constant.js b/src/constant.js index 4ac738f..55083f9 100644 --- a/src/constant.js +++ b/src/constant.js @@ -1,3 +1,4 @@ +// @flow // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -18,83 +19,79 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -'use strict'; - -var CONSTANT = { - DATA_TYPES: { - // date time formats - DATE: 'DATE', - TIME: 'TIME', - DATETIME: 'DATETIME', - - // number formats - NUMBER: 'NUMBER', - INT: 'INT', - FLOAT: 'FLOAT', - CURRENCY: 'CURRENCY', - PERCENT: 'PERCENT', - - // string types: - STRING: 'STRING', - CITY: 'CITY', - ZIPCODE: 'ZIPCODE', - - // boolean type - BOOLEAN: 'BOOLEAN', - - // geometry - GEOMETRY: 'GEOMETRY', - GEOMETRY_FROM_STRING: 'GEOMETRY_FROM_STRING', - PAIR_GEOMETRY_FROM_STRING: 'PAIR_GEOMETRY_FROM_STRING', - - NONE: 'NONE' - }, - - CATEGORIES: { - GEOMETRY: 'GEOMETRY', - TIME: 'TIME', - DIMENSION: 'DIMENSION', - MEASURE: 'MEASURE' - }, - - BOOLEAN_TRUE_VALUES: ['true', 'yes', '1'], - BOOLEAN_FALSE_VALUES: ['false', 'no', '0'], - - NULL: 'NULL' -}; +export const DATA_TYPES = { + // date time formats + DATE: 'DATE', + TIME: 'TIME', + DATETIME: 'DATETIME', -CONSTANT.POSSIBLE_TYPES = {}; + // number formats + NUMBER: 'NUMBER', + INT: 'INT', + FLOAT: 'FLOAT', + CURRENCY: 'CURRENCY', + PERCENT: 'PERCENT', -CONSTANT.POSSIBLE_TYPES[CONSTANT.CATEGORIES.GEOMETRY] = [ - CONSTANT.DATA_TYPES.GEOMETRY_FROM_STRING, - CONSTANT.DATA_TYPES.PAIR_GEOMETRY_FROM_STRING, - CONSTANT.DATA_TYPES.GEOMETRY -]; + // string types: + STRING: 'STRING', + CITY: 'CITY', + ZIPCODE: 'ZIPCODE', -CONSTANT.POSSIBLE_TYPES[CONSTANT.CATEGORIES.TIME] = [ - CONSTANT.DATA_TYPES.DATETIME, - CONSTANT.DATA_TYPES.DATE, - CONSTANT.DATA_TYPES.TIME -]; + // boolean type + BOOLEAN: 'BOOLEAN', -CONSTANT.POSSIBLE_TYPES[CONSTANT.CATEGORIES.DIMENSION] = [ - CONSTANT.DATA_TYPES.STRING, - CONSTANT.DATA_TYPES.BOOLEAN, - CONSTANT.DATA_TYPES.CITY, - CONSTANT.DATA_TYPES.ZIPCODE -]; + // geometry + GEOMETRY: 'GEOMETRY', + GEOMETRY_FROM_STRING: 'GEOMETRY_FROM_STRING', + PAIR_GEOMETRY_FROM_STRING: 'PAIR_GEOMETRY_FROM_STRING', -CONSTANT.POSSIBLE_TYPES[CONSTANT.CATEGORIES.MEASURE] = [ - CONSTANT.DATA_TYPES.NUMBER, - CONSTANT.DATA_TYPES.INT, - CONSTANT.DATA_TYPES.FLOAT, - CONSTANT.DATA_TYPES.CURRENCY, - CONSTANT.DATA_TYPES.PERCENT -]; + NONE: 'NONE' +}; + +export const CATEGORIES: $ReadOnly = { + GEOMETRY: 'GEOMETRY', + TIME: 'TIME', + DIMENSION: 'DIMENSION', + MEASURE: 'MEASURE' +}; -CONSTANT.TYPES_TO_CATEGORIES = Object.keys(CONSTANT.POSSIBLE_TYPES) +export const BOOLEAN_TRUE_VALUES = ['true', 'yes', '1']; +export const BOOLEAN_FALSE_VALUES = ['false', 'no', '0']; + +export const NULL = 'NULL'; + +export const POSSIBLE_TYPES = { + [CATEGORIES.GEOMETRY]: [ + DATA_TYPES.GEOMETRY_FROM_STRING, + DATA_TYPES.PAIR_GEOMETRY_FROM_STRING, + DATA_TYPES.GEOMETRY + ], + + [CATEGORIES.TIME]: [ + DATA_TYPES.DATETIME, + DATA_TYPES.DATE, + DATA_TYPES.TIME + ], + + [CATEGORIES.DIMENSION]: [ + DATA_TYPES.STRING, + DATA_TYPES.BOOLEAN, + DATA_TYPES.CITY, + DATA_TYPES.ZIPCODE + ], + + [CATEGORIES.MEASURE]: [ + DATA_TYPES.NUMBER, + DATA_TYPES.INT, + DATA_TYPES.FLOAT, + DATA_TYPES.CURRENCY, + DATA_TYPES.PERCENT + ] +}; + +export const TYPES_TO_CATEGORIES = Object.keys(POSSIBLE_TYPES) .reduce(function generateTypeToCategoryMap(res, category) { - CONSTANT.POSSIBLE_TYPES[category].forEach(function loopAcrossTypes(type) { + POSSIBLE_TYPES[category].forEach(function loopAcrossTypes(type) { res[type] = category; }); return res; @@ -105,39 +102,37 @@ CONSTANT.TYPES_TO_CATEGORIES = Object.keys(CONSTANT.POSSIBLE_TYPES) // here's trying to determine a more accuraet data type of the column. // later on, users still can override the data type. // this will affect how we trasnform(aggregation), formating the data. -CONSTANT.VALIDATORS = [ +export const VALIDATORS = [ // geometry - CONSTANT.DATA_TYPES.GEOMETRY, - CONSTANT.DATA_TYPES.GEOMETRY_FROM_STRING, - CONSTANT.DATA_TYPES.PAIR_GEOMETRY_FROM_STRING, + DATA_TYPES.GEOMETRY, + DATA_TYPES.GEOMETRY_FROM_STRING, + DATA_TYPES.PAIR_GEOMETRY_FROM_STRING, // true/false, 0/1 - CONSTANT.DATA_TYPES.BOOLEAN, + DATA_TYPES.BOOLEAN, // prefix/postfix rules - CONSTANT.DATA_TYPES.CURRENCY, - CONSTANT.DATA_TYPES.PERCENT, + DATA_TYPES.CURRENCY, + DATA_TYPES.PERCENT, // times - CONSTANT.DATA_TYPES.DATETIME, - CONSTANT.DATA_TYPES.DATE, - CONSTANT.DATA_TYPES.TIME, + DATA_TYPES.DATETIME, + DATA_TYPES.DATE, + DATA_TYPES.TIME, // numbers - CONSTANT.DATA_TYPES.INT, - CONSTANT.DATA_TYPES.FLOAT, - CONSTANT.DATA_TYPES.NUMBER, + DATA_TYPES.INT, + DATA_TYPES.FLOAT, + DATA_TYPES.NUMBER, // strings - CONSTANT.DATA_TYPES.ZIPCODE, - CONSTANT.DATA_TYPES.CITY, - CONSTANT.DATA_TYPES.STRING + DATA_TYPES.ZIPCODE, + DATA_TYPES.CITY, + DATA_TYPES.STRING ]; -CONSTANT.TIME_VALIDATORS = [ - CONSTANT.DATA_TYPES.DATETIME, - CONSTANT.DATA_TYPES.DATE, - CONSTANT.DATA_TYPES.TIME +export const TIME_VALIDATORS = [ + DATA_TYPES.DATETIME, + DATA_TYPES.DATE, + DATA_TYPES.TIME ]; - -module.exports = CONSTANT; diff --git a/src/regex-list.js b/src/regex-list.js index f9ada49..637f92b 100644 --- a/src/regex-list.js +++ b/src/regex-list.js @@ -1,3 +1,4 @@ +// @flow // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -20,7 +21,7 @@ 'use strict'; -var RegexList = { +export const RegexList = { // accepts: 10, 2.3, +4,000, -5,023.234, 2.3e+2, 4,234.56e-2, $23,203, 23.45% isNumber: /^(\+|\-)?\$?[\d,]*\.?\d+((e|E)(\+|\-)\d+)?%?$/, @@ -54,5 +55,3 @@ var RegexList = { isPairwisePointGeometry: /(\+|\-)?\d*\.\d*,(\+|\-)?\d*\.\d*/ }; - -module.exports = RegexList; diff --git a/src/utils.js b/src/utils.js index 839c0f9..a9909bc 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,3 +1,4 @@ +// @flow // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -18,10 +19,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -'use strict'; - -var CONSTANT = require('./constant'); -var RegexList = require('./regex-list'); +import {NULL, DATA_TYPES, BOOLEAN_TRUE_VALUES, BOOLEAN_FALSE_VALUES} from './constant'; +import RegexList from './regex-list'; /* eslint-disable max-len*/ /** @@ -34,25 +33,25 @@ function union(arr) { } // GENERATE ALL OF THE TIME REGEXES -var HH = '\\d{1,2}'; -var H = '\\d{1,2}'; -var h = '\\d{1,2}'; -var m = '\\d{1,2}'; -var s = '\\d{1,2}'; -var ss = '\\d{2}'; -var SSSS = '(\\.\\d{1,6})'; -var mm = '\\d{2}'; -var Z = '(\\+|-)\\d{1,2}:\\d{1,2}'; -var ZZ = '(\\+|-)(\\d{4}|\\d{1,2}:\\d{2})'; -var a = '(am|pm)'; +const HH = '\\d{1,2}'; +const H = '\\d{1,2}'; +const h = '\\d{1,2}'; +const m = '\\d{1,2}'; +const s = '\\d{1,2}'; +const ss = '\\d{2}'; +const SSSS = '(\\.\\d{1,6})'; +const mm = '\\d{2}'; +const Z = '(\\+|-)\\d{1,2}:\\d{1,2}'; +const ZZ = '(\\+|-)(\\d{4}|\\d{1,2}:\\d{2})'; +const a = '(am|pm)'; // 1513629453477 -var X = '\\b\\d{12,13}\\b'; +const X = '\\b\\d{12,13}\\b'; // 123456789 123456789.123 -var x = '\\b\\d{9,10}(\\.\\d{1,3})?\\b'; +const x = '\\b\\d{9,10}(\\.\\d{1,3})?\\b'; -var TIME_FORMAT_STRINGS = [ +const TIME_FORMAT_STRINGS = [ 'X', 'x', 'H:m', @@ -65,7 +64,7 @@ var TIME_FORMAT_STRINGS = [ 'HH:mm:ss.SSSSZZ' ].reverse(); // the reverse is important to put the more specific regexs higher in the order -var TIME_FORMAT_REGEX_STRINGS = [ +const TIME_FORMAT_REGEX_STRINGS = [ X, x, H + ':' + m, @@ -80,19 +79,19 @@ var TIME_FORMAT_REGEX_STRINGS = [ // something like: // {'(\d{2)....': 'M-D-YYYY'} -var TIME_FORMAT_REGEX_MAP = TIME_FORMAT_STRINGS +const TIME_FORMAT_REGEX_MAP = TIME_FORMAT_STRINGS .reduce(function generateRegexMap(timeFormats, str, index) { timeFormats[TIME_FORMAT_REGEX_STRINGS[index]] = str; return timeFormats; }, {}); -var ALL_TIME_FORMAT_REGEX_STR = union(Object.keys(TIME_FORMAT_REGEX_MAP)); -var ALL_TIME_FORMAT_REGEX = new RegExp('^' + ALL_TIME_FORMAT_REGEX_STR + '$', 'i'); +const ALL_TIME_FORMAT_REGEX_STR = union(Object.keys(TIME_FORMAT_REGEX_MAP)); +const ALL_TIME_FORMAT_REGEX = new RegExp('^' + ALL_TIME_FORMAT_REGEX_STR + '$', 'i'); // GENERATE ALL DATE FORMATS -var YYYY = '\\d{2,4}'; -var M = '\\d{1,2}'; -var MMM = union([ +const YYYY = '\\d{2,4}'; +const M = '\\d{1,2}'; +const MMM = union([ 'Jan', 'Feb', 'Mar', @@ -106,7 +105,7 @@ var MMM = union([ 'Nov', 'Dec' ]); -var MMMM = union([ +const MMMM = union([ 'January', 'February', 'March', @@ -120,11 +119,11 @@ var MMMM = union([ 'November', 'December' ]); -var D = '\\d{1,2}'; -var DD = '\\d{2}'; -var Do = '\\d{1,2}(st|nd|rd|th)'; +const D = '\\d{1,2}'; +const DD = '\\d{2}'; +const Do = '\\d{1,2}(st|nd|rd|th)'; -var dateFormatRegexStrings = [ +const dateFormatRegexStrings = [ YYYY + '-' + M + '-' + D, M + '\\/' + D + '\\/' + YYYY, MMMM + ' ' + DD + ', ' + YYYY, @@ -132,7 +131,7 @@ var dateFormatRegexStrings = [ MMMM + ' ' + Do + ', ' + YYYY, MMM + ' ' + Do + ', ' + YYYY ]; -var dateFormatStrings = [ +const dateFormatStrings = [ 'YYYY-M-D', 'M/D/YYYY', 'MMMM DD, YYYY', @@ -140,11 +139,11 @@ var dateFormatStrings = [ 'MMMM Do, YYYY', 'MMM Do, YYYY' ]; -var DATE_FORMAT_REGEX = new RegExp('^' + union(dateFormatRegexStrings) + '$', 'i'); +const DATE_FORMAT_REGEX = new RegExp('^' + union(dateFormatRegexStrings) + '$', 'i'); // something like: // {'(\d{2)....': 'M-D-YYYY'} -var DATE_FORMAT_REGEX_MAP = dateFormatStrings +const DATE_FORMAT_REGEX_MAP = dateFormatStrings .reduce(function generateRegexMap(dateFormats, str, index) { dateFormats[dateFormatRegexStrings[index]] = str; return dateFormats; @@ -153,11 +152,11 @@ var DATE_FORMAT_REGEX_MAP = dateFormatStrings // COMPUTE THEIR CROSS PRODUCT // {'SOME HELLISH REGEX': 'YYYY HH:MM:SS'} -var DATE_TIME_MAP = Object.keys(DATE_FORMAT_REGEX_MAP) +const DATE_TIME_MAP = Object.keys(DATE_FORMAT_REGEX_MAP) .reduce(function reduceDate(dateTimes, dateRegex) { - var dateStr = DATE_FORMAT_REGEX_MAP[dateRegex]; + const dateStr = DATE_FORMAT_REGEX_MAP[dateRegex]; Object.keys(TIME_FORMAT_REGEX_MAP).forEach(function loopAcrosTimes(timeRegex) { - var timeStr = TIME_FORMAT_REGEX_MAP[timeRegex]; + const timeStr = TIME_FORMAT_REGEX_MAP[timeRegex]; dateTimes[dateRegex + ' ' + timeRegex] = dateStr + ' ' + timeStr; dateTimes[dateRegex + 'T' + timeRegex] = dateStr + 'T' + timeStr; dateTimes[timeRegex + 'T' + dateRegex] = timeStr + 'T' + dateStr; @@ -165,7 +164,7 @@ var DATE_TIME_MAP = Object.keys(DATE_FORMAT_REGEX_MAP) }); return dateTimes; }, {}); -var ALL_DATE_TIME_REGEX = new RegExp(union(Object.keys(DATE_TIME_MAP))); +const ALL_DATE_TIME_REGEX = new RegExp(union(Object.keys(DATE_TIME_MAP))); /** * Generate a function to discover which time format a value is @@ -174,13 +173,13 @@ var ALL_DATE_TIME_REGEX = new RegExp(union(Object.keys(DATE_TIME_MAP))); * @return {Func} to the format checker */ function whichFormatGenerator(formatRegex, regexMap) { - return function whichFormat(value) { + return function whichFormat(value: string) { if (formatRegex.test(value)) { - var regexes = Object.keys(regexMap); - for (var i = 0; i < regexes.length; i++) { - var regex = regexes[i]; - var format = regexMap[regex]; - var newRegex = new RegExp(regex); + const regexes = Object.keys(regexMap); + for (let i = 0; i < regexes.length; i++) { + const regex = regexes[i]; + const format = regexMap[regex]; + const newRegex = new RegExp(regex); if (newRegex.test(value)) { return format; } @@ -190,59 +189,50 @@ function whichFormatGenerator(formatRegex, regexMap) { }; } -var whichFormatTime = whichFormatGenerator(ALL_TIME_FORMAT_REGEX, TIME_FORMAT_REGEX_MAP); -var whichFormatDate = whichFormatGenerator(DATE_FORMAT_REGEX, DATE_FORMAT_REGEX_MAP); -var whichFormatDateTime = whichFormatGenerator(ALL_DATE_TIME_REGEX, DATE_TIME_MAP); - -var Utils = { - buildRegexCheck: function buildRegexCheck(regexId) { - return function check(value) { - return RegexList[regexId].test(value.toString()); - }; - }, - - detectTimeFormat: function detectTimeFormat(value, type) { - switch (type) { - case CONSTANT.DATA_TYPES.DATETIME: - return whichFormatDateTime(value); - case CONSTANT.DATA_TYPES.DATE: - default: - return whichFormatDate(value); - case CONSTANT.DATA_TYPES.TIME: - return whichFormatTime(value); - } - }, +export const whichFormatTime = whichFormatGenerator(ALL_TIME_FORMAT_REGEX, TIME_FORMAT_REGEX_MAP); +export const whichFormatDate = whichFormatGenerator(DATE_FORMAT_REGEX, DATE_FORMAT_REGEX_MAP); +export const whichFormatDateTime = whichFormatGenerator(ALL_DATE_TIME_REGEX, DATE_TIME_MAP); - findFirstNonNullValue: function findFirstNonNullValue(data, column) { - for (var i = 0; i < data.length; i++) { - if (data[i][column] !== null && data[i][column] !== CONSTANT.NULL) { - return data[i][column]; - } +export function buildRegexCheck(regexId: $Keys) { + return function check(value: string) { + return RegexList[regexId].test(value.toString()); + }; +} + +export function detectTimeFormat(value: string, type: $Values) { + switch (type) { + case DATA_TYPES.DATETIME: + return whichFormatDateTime(value); + case DATA_TYPES.DATE: + default: + return whichFormatDate(value); + case DATA_TYPES.TIME: + return whichFormatTime(value); + } +} + +export function findFirstNonNullValue(data: Object[], column) { + for (let i = 0; i < data.length; i++) { + if (data[i][column] !== null && data[i][column] !== NULL) { + return data[i][column]; } - return null; - }, - - isBoolean: function isBoolean(value) { - return CONSTANT.BOOLEAN_TRUE_VALUES - .concat(CONSTANT.BOOLEAN_FALSE_VALUES) - .indexOf(String(value).toLowerCase()) > -1; - }, - - isGeographic: function isGeographic(value) { - return Boolean(value) && typeof value === 'object' && - value.hasOwnProperty('type') && value.hasOwnProperty('coordinates'); - }, - - // string types - isString: function isString(value) { - return typeof value === 'string'; - }, - - whichFormatTime: whichFormatGenerator(ALL_TIME_FORMAT_REGEX, TIME_FORMAT_REGEX_MAP), - whichFormatDate: whichFormatGenerator(DATE_FORMAT_REGEX, DATE_FORMAT_REGEX_MAP), - whichFormatDateTime: whichFormatGenerator(ALL_DATE_TIME_REGEX, DATE_TIME_MAP) -}; + } + return null; +} -/* eslint-enable max-len*/ +export function isBoolean(value: mixed) { + return BOOLEAN_TRUE_VALUES + .concat(BOOLEAN_FALSE_VALUES) + .indexOf(String(value).toLowerCase()) > -1; +} + +export function isGeographic(value: mixed) { + return Boolean(value) && typeof value === 'object' && value !== null && + value.hasOwnProperty('type') && value.hasOwnProperty('coordinates'); +} + +export function isString(value: mixed) { + return typeof value === 'string'; +} -module.exports = Utils; +/* eslint-enable max-len*/ diff --git a/src/validator-map.js b/src/validator-map.js index 8854868..0212895 100644 --- a/src/validator-map.js +++ b/src/validator-map.js @@ -1,3 +1,4 @@ +// @flow // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -18,13 +19,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -'use strict'; +import {DATA_TYPES} from './constant'; +import Utils from './utils'; -var CONSTANT = require('./constant'); -var Utils = require('./utils'); - -var DATA_TYPES = CONSTANT.DATA_TYPES; -var VALIDATOR_MAP = {}; +const VALIDATOR_MAP = {}; // geometry VALIDATOR_MAP[DATA_TYPES.GEOMETRY] = Utils.isGeographic;