hadron-type-checker
Advanced tools
Comparing version 1.3.0 to 2.0.0
@@ -7,5 +7,5 @@ 'use strict'; | ||
const isNumber = require('lodash.isnumber'); | ||
const isEmpty = require('lodash.isempty'); | ||
const has = require('lodash.has'); | ||
const find = require('lodash.find'); | ||
const keys = require('lodash.keys'); | ||
const without = require('lodash.without'); | ||
const toNumber = require('lodash.tonumber'); | ||
@@ -21,2 +21,7 @@ const toString = require('lodash.tostring'); | ||
const Decimal128 = bson.Decimal128; | ||
const Binary = bson.Binary; | ||
const BSONRegExp = bson.BSONRegExp; | ||
const Code = bson.Code; | ||
const Symbol = bson.Symbol; | ||
const Timestamp = bson.Timestamp; | ||
@@ -34,2 +39,19 @@ /** | ||
/** | ||
* True constant. | ||
*/ | ||
const TRUE = 'true'; | ||
/** | ||
* Long constant. | ||
*/ | ||
const LONG = 'Long'; | ||
const INT_32 = 'Int32'; | ||
const INT_64 = 'Int64'; | ||
const DOUBLE = 'Double'; | ||
const DECIMAL_128 = 'Decimal128'; | ||
const OBJECT_TYPE = '[object Object]'; | ||
const EMPTY = ''; | ||
/** | ||
* The bson type field. | ||
@@ -54,6 +76,9 @@ */ | ||
const BSON_INT64_MAX = Math.pow(2, 63) - 1; | ||
const BSON_INT64_MIN = -(BSON_INT64_MAX); | ||
/** | ||
* The max double value. | ||
* The number regex. | ||
*/ | ||
const MAX_DBL = Number.MAX_SAFE_INTEGER; | ||
const NUMBER_REGEX = /^-?\d+$/; | ||
@@ -70,25 +95,25 @@ /** | ||
function toDate(object) { | ||
const toDate = (object) => { | ||
return new Date(object); | ||
} | ||
}; | ||
function toMinKey() { | ||
const toMinKey = () => { | ||
return new MinKey(); | ||
} | ||
}; | ||
function toMaxKey() { | ||
const toMaxKey = () => { | ||
return new MaxKey(); | ||
} | ||
}; | ||
function toUndefined() { | ||
const toUndefined = () => { | ||
return undefined; | ||
} | ||
}; | ||
function toNull() { | ||
const toNull = () => { | ||
return null; | ||
} | ||
}; | ||
function toBoolean(object) { | ||
const toBoolean = (object) => { | ||
if (isString(object)) { | ||
if (object.toLowerCase() === 'true') { | ||
if (object.toLowerCase() === TRUE) { | ||
return true; | ||
@@ -102,5 +127,5 @@ } | ||
return false; | ||
} | ||
}; | ||
function toObject(object) { | ||
const toObject = (object) => { | ||
if (isPlainObject(object)) { | ||
@@ -110,5 +135,5 @@ return object; | ||
return {}; | ||
} | ||
}; | ||
function toArray(object) { | ||
const toArray = (object) => { | ||
if (isArray(object)) { | ||
@@ -121,17 +146,26 @@ return object; | ||
return [ object ]; | ||
} | ||
}; | ||
function toInt32(object) { | ||
return new Int32(toNumber(object)); | ||
} | ||
const toInt32 = (object) => { | ||
const number = toNumber(object); | ||
if (number >= BSON_INT32_MIN && number <= BSON_INT32_MAX) { | ||
return new Int32(number); | ||
} | ||
throw new Error(`Value ${number} is outside the valid Int32 range`); | ||
}; | ||
function toInt64(object) { | ||
return Long.fromNumber(toNumber(object)); | ||
} | ||
const toInt64 = (object) => { | ||
const number = toNumber(object); | ||
if (number >= BSON_INT64_MIN && number <= BSON_INT64_MAX) { | ||
return Long.fromNumber(number); | ||
} | ||
throw new Error(`Value ${number} is outside the valid Int64 range`); | ||
}; | ||
function toDouble(object) { | ||
return new Double(toNumber(object)); | ||
} | ||
const toDouble = (object) => { | ||
const number = toNumber(object); | ||
return new Double(number); | ||
}; | ||
function toDecimal128(object) { | ||
const toDecimal128 = (object) => { | ||
/* | ||
@@ -141,14 +175,35 @@ If converting a BSON Object, extract the value before converting to a string. | ||
if (has(object, BSON_TYPE) && includes(NUMBER_TYPES, object._bsontype)) { | ||
object = object._bsontype === 'Long' ? object.toNumber() : object.valueOf(); | ||
object = object._bsontype === LONG ? object.toNumber() : object.valueOf(); | ||
} | ||
return Decimal128.fromString(String(object)); | ||
} | ||
}; | ||
function toObjectID(object) { | ||
if (object === '') { | ||
const toObjectID = (object) => { | ||
if (!isString(object) || object === '') { | ||
return new bson.ObjectID(); | ||
} | ||
return bson.ObjectID.createFromHexString(object); | ||
} | ||
}; | ||
const toBinary = (object) => { | ||
return new Binary(String(object), Binary.SUBTYPE_DEFAULT); | ||
}; | ||
const toRegex = (object) => { | ||
return new BSONRegExp(String(object)); | ||
}; | ||
const toCode = (object) => { | ||
return new Code(String(object), {}); | ||
}; | ||
const toSymbol = (object) => { | ||
return new Symbol(String(object)); | ||
}; | ||
const toTimestamp = (object) => { | ||
const number = toNumber(object); | ||
return Timestamp.fromNumber(number); | ||
}; | ||
/** | ||
@@ -158,30 +213,28 @@ * The functions to cast to a type. | ||
const CASTERS = { | ||
'Array': toArray, | ||
'Binary': toBinary, | ||
'Boolean': toBoolean, | ||
'Code': toCode, | ||
'Date': toDate, | ||
'Decimal128': toDecimal128, | ||
'Double': toDouble, | ||
'Int32': toInt32, | ||
'Int64': toInt64, | ||
'Double': toDouble, | ||
'Decimal128': toDecimal128, | ||
'Date': toDate, | ||
'MaxKey': toMaxKey, | ||
'MinKey': toMinKey, | ||
'MaxKey': toMaxKey, | ||
'Undefined': toUndefined, | ||
'Null': toNull, | ||
'Boolean': toBoolean, | ||
'Object': toObject, | ||
'ObjectID': toObjectID, | ||
'BSONRegexp': toRegex, | ||
'String': toString, | ||
'Object': toObject, | ||
'Array': toArray, | ||
'ObjectID': toObjectID | ||
'Symbol': toSymbol, | ||
'Timestamp': toTimestamp, | ||
'Undefined': toUndefined | ||
}; | ||
/** | ||
* A test that returns the types is passing. | ||
* An array of all bson types. | ||
*/ | ||
class Test { | ||
constructor(tester, types) { | ||
this.tester = tester; | ||
this.types = types; | ||
} | ||
} | ||
const TYPES = keys(CASTERS); | ||
const NUMBER_REGEX = /^-?\d+$/; | ||
/** | ||
@@ -212,102 +265,6 @@ * Checks if a string is an int32. | ||
/** | ||
* Checks if integer can be cast to double. | ||
*/ | ||
class IntDblCheck { | ||
test(string) { | ||
if (NUMBER_REGEX.test(string)) { | ||
var value = toNumber(string); | ||
return value >= -MAX_DBL && value <= MAX_DBL; | ||
} | ||
return false; | ||
} | ||
} | ||
const DOUBLE_REGEX = /^-?(\d*\.)?\d{1,15}$/; | ||
/** | ||
* Checks if the value can be cast to a double. | ||
*/ | ||
class DoubleCheck { | ||
test(string) { | ||
if (DOUBLE_REGEX.test(string)) { | ||
var value = toNumber(string); | ||
return value >= -MAX_DBL && value <= MAX_DBL; | ||
} | ||
return false; | ||
} | ||
} | ||
var PARSE_STRING_REGEXP = /^(?=\d)(\+|\-)?(\d+|(\d*\.\d*))?(E|e)?([\-\+])?(\d+)?$/; | ||
var PARSE_INF_REGEXP = /^(\+|\-)?(Infinity|inf)$/i; | ||
var PARSE_NAN_REGEXP = /^(\+|\-)?NaN$/i; | ||
/** | ||
* Checks if the value can be cast to a decimal 128. | ||
*/ | ||
class Decimal128Check { | ||
test(string) { | ||
const stringMatch = string.match(PARSE_STRING_REGEXP); | ||
const infMatch = string.match(PARSE_INF_REGEXP); | ||
const nanMatch = string.match(PARSE_NAN_REGEXP); | ||
const regex = stringMatch || infMatch || nanMatch; | ||
const exp = stringMatch && stringMatch[4] && stringMatch[2] === undefined; | ||
return string.length !== 0 && regex && !exp; | ||
} | ||
} | ||
/** | ||
* Checks if a string is a date. | ||
*/ | ||
class DateCheck { | ||
test(string) { | ||
return isFinite(toDate(string).getTime()); | ||
} | ||
} | ||
const INT32_CHECK = new Int32Check(); | ||
const INT64_CHECK = new Int64Check(); | ||
const INT_DBL_CHECK = new IntDblCheck(); | ||
const DOUBLE_CHECK = new DoubleCheck(); | ||
const DECIMAL_128_CHECK = new Decimal128Check(); | ||
const DATE_CHECK = new DateCheck(); | ||
/** | ||
* The various string tests, | ||
* excluding dates which are on their own dimension. | ||
*/ | ||
const STRING_TESTS = [ | ||
new Test(/^$/, [ 'String', 'Null', 'MinKey', 'MaxKey', 'Object', 'Array', 'ObjectID']), | ||
new Test(INT32_CHECK, [ 'Int32', 'Int64', 'Double', 'String', 'Object', 'Array' ]), | ||
new Test(INT_DBL_CHECK, [ 'Int64', 'Double', 'String', 'Object', 'Array' ]), | ||
new Test(INT64_CHECK, [ 'Int64', 'String', 'Object', 'Array' ]), | ||
new Test(DOUBLE_CHECK, [ 'Double', 'String', 'Object', 'Array' ]), | ||
new Test(/^(null)$/, [ 'Null', 'String', 'Object', 'Array' ]), | ||
new Test(/^(undefined)$/, [ 'Undefined', 'String', 'Object', 'Array' ]), | ||
new Test(/^(true|false)$/, [ 'Boolean', 'String', 'Object', 'Array' ]), | ||
new Test(/^\/(.*)\/$/, [ 'BSONRegExp', 'String', 'Object', 'Array' ]), | ||
new Test(/(^$)|^[A-Fa-f0-9]{24}$/, [ 'String', 'Object', 'Array', 'ObjectID' ]) | ||
]; | ||
/** | ||
* String tests with high precision support, | ||
* excluding dates which are on their own dimension. | ||
*/ | ||
const HP_STRING_TESTS = [ | ||
new Test(/^$/, [ 'String', 'Null', 'MinKey', 'MaxKey', 'Object', 'Array', 'ObjectID' ]), | ||
new Test(INT32_CHECK, [ 'Int32', 'Int64', 'Double', 'Decimal128', 'String', 'Object', 'Array' ]), | ||
new Test(INT_DBL_CHECK, [ 'Int64', 'Double', 'Decimal128', 'String', 'Object', 'Array' ]), | ||
new Test(INT64_CHECK, [ 'Int64', 'Decimal128', 'String', 'Object', 'Array' ]), | ||
new Test(DOUBLE_CHECK, [ 'Double', 'Decimal128', 'String', 'Object', 'Array' ]), | ||
new Test(DECIMAL_128_CHECK, [ 'Decimal128', 'String', 'Object', 'Array' ]), | ||
new Test(/^(null)$/, [ 'Null', 'String', 'Object', 'Array' ]), | ||
new Test(/^(undefined)$/, [ 'Undefined', 'String', 'Object', 'Array' ]), | ||
new Test(/^(true|false)$/, [ 'Boolean', 'String', 'Object', 'Array' ]), | ||
new Test(/^\/(.*)\/$/, [ 'BSONRegExp', 'String', 'Object', 'Array' ]), | ||
new Test(/(^$)|^[A-Fa-f0-9]{24}$/, [ 'String', 'Object', 'Array', 'ObjectID' ]) | ||
]; | ||
/** | ||
* Gets the BSON type for a JS number. | ||
@@ -319,11 +276,11 @@ * | ||
*/ | ||
function numberToBsonType(number) { | ||
const numberToBsonType = (number) => { | ||
var string = toString(number); | ||
if (INT32_CHECK.test(string)) { | ||
return 'Int32'; | ||
return INT_32; | ||
} else if (INT64_CHECK.test(string)) { | ||
return 'Int64'; | ||
return INT_64; | ||
} | ||
return 'Double'; | ||
} | ||
return DOUBLE; | ||
}; | ||
@@ -349,3 +306,3 @@ /** | ||
} | ||
return result === '[object Object]' ? '' : result; | ||
return result === OBJECT_TYPE ? EMPTY : result; | ||
} | ||
@@ -371,4 +328,4 @@ | ||
if (has(object, BSON_TYPE)) { | ||
if (object._bsontype === 'Long') { | ||
return 'Int64'; | ||
if (object._bsontype === LONG) { | ||
return INT_64; | ||
} | ||
@@ -383,3 +340,2 @@ return object._bsontype; | ||
* | ||
* @param {Object} object - The object. | ||
* @param {Boolean} highPrecisionSupport - If Decimal128 is supported or not. | ||
@@ -389,47 +345,10 @@ * | ||
*/ | ||
castableTypes(object, highPrecisionSupport = false) { | ||
if (isString(object)) { | ||
return this._stringTypes(object, highPrecisionSupport); | ||
} else if (isNumber(object)) { | ||
return this._stringTypes(String(object), highPrecisionSupport); | ||
} else if (has(object, BSON_TYPE) && this._isNumberType(object._bsontype)) { | ||
var rawValue = object._bsontype === 'Long' ? object.toNumber() : object.valueOf(); | ||
return this._stringTypes(String(rawValue), highPrecisionSupport); | ||
} else if (isPlainObject(object)) { | ||
if (isEmpty(object)) { | ||
return [ 'Object', 'Array' ]; | ||
} | ||
return [ 'Object' ]; | ||
} else if (isArray(object)) { | ||
if (isEmpty(object)) { | ||
return [ 'Object', 'Array' ]; | ||
} | ||
return [ 'Array' ]; | ||
castableTypes(highPrecisionSupport = false) { | ||
if (highPrecisionSupport === true) { | ||
return TYPES; | ||
} | ||
return [ this.type(object), 'String', 'Object', 'Array' ]; | ||
return without(TYPES, DECIMAL_128); | ||
} | ||
_isNumberType(bsontype) { | ||
return includes(NUMBER_TYPES, bsontype); | ||
} | ||
_stringTypes(string, highPrecisionSupport) { | ||
let types = [ 'String', 'Object', 'Array' ]; | ||
var passing = find(highPrecisionSupport ? HP_STRING_TESTS : STRING_TESTS, (test) => { | ||
return test.tester.test(string); | ||
}); | ||
if (passing) { | ||
types = passing.types; | ||
} | ||
// Add date dynamically to the existing types lists, as it is on a | ||
// completely different dimension to numeric types and so significantly | ||
// more complicated to enumerate all valid combinations | ||
if (DATE_CHECK.test(string)) { | ||
types = ['Date', ...types]; | ||
} | ||
return types; | ||
} | ||
} | ||
module.exports = new TypeChecker(); |
@@ -7,3 +7,3 @@ { | ||
"homepage": "https://github.com/mongodb-js/hadron-type-checker", | ||
"version": "1.3.0", | ||
"version": "2.0.0", | ||
"repository": { | ||
@@ -28,14 +28,13 @@ "type": "git", | ||
"bson": "^1.0.1", | ||
"lodash.find": "^4.4.0", | ||
"lodash.has": "^4.4.0", | ||
"lodash.includes": "^4.3.0", | ||
"lodash.isarray": "^4.0.0", | ||
"lodash.isempty": "^4.0.0", | ||
"lodash.isinteger": "^4.0.4", | ||
"lodash.isnumber": "^3.0.3", | ||
"lodash.isplainobject": "^4.0.4", | ||
"lodash.isstring": "^4.0.1", | ||
"lodash.toarray": "^4.2.4", | ||
"lodash.keys": "^4.2.0", | ||
"lodash.tonumber": "^4.0.2", | ||
"lodash.toplainobject": "^4.0.4", | ||
"lodash.tostring": "^4.1.3" | ||
"lodash.tostring": "^4.1.3", | ||
"lodash.without": "^4.4.0" | ||
}, | ||
@@ -42,0 +41,0 @@ "devDependencies": { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
12
19160
298
+ Addedlodash.isinteger@^4.0.4
+ Addedlodash.keys@^4.2.0
+ Addedlodash.without@^4.4.0
+ Addedlodash.isinteger@4.0.4(transitive)
+ Addedlodash.keys@4.2.0(transitive)
+ Addedlodash.without@4.4.0(transitive)
- Removedlodash.find@^4.4.0
- Removedlodash.isempty@^4.0.0
- Removedlodash.toarray@^4.2.4
- Removedlodash.toplainobject@^4.0.4
- Removedlodash.find@4.6.0(transitive)
- Removedlodash.isempty@4.4.0(transitive)
- Removedlodash.toarray@4.4.0(transitive)
- Removedlodash.toplainobject@4.2.0(transitive)