Comparing version 9.3.1 to 9.3.2
@@ -5,3 +5,2 @@ /** | ||
var util = require('util'); | ||
var _ = require('lodash'); | ||
@@ -21,9 +20,4 @@ var validateRecursive = require('./helpers/validate-recursive'); | ||
// Jump into recursive validation | ||
var errors = []; | ||
// Avoid damaging `expected` | ||
expected = _.cloneDeep(expected); | ||
// TODO: add sufficient tests to ensure this is never a problem, then remove this to improve performance. | ||
// Jump into recursive validation | ||
var result = validateRecursive(expected, actual, errors, []); | ||
@@ -37,3 +31,2 @@ | ||
// TODO: | ||
// Note that it would be more efficient to pass in a list of error codes | ||
@@ -46,4 +39,8 @@ // to ignore when calling `validateRecursive`, rather than iterating through | ||
var err = consolidateErrors(errors, 'coercing value'); | ||
if (err) throw err; | ||
else return result; | ||
if (err) { | ||
throw err; | ||
} | ||
else { | ||
return result; | ||
} | ||
}; |
@@ -5,3 +5,2 @@ /** | ||
var _ = require('lodash'); | ||
var rebuildSanitized = require('./helpers/sanitize'); | ||
@@ -23,3 +22,3 @@ | ||
module.exports = function dehydrate (value, allowNull, dontStringifyFunctions) { | ||
return rebuildSanitized(value,allowNull,dontStringifyFunctions); | ||
return rebuildSanitized(value, allowNull, dontStringifyFunctions); | ||
}; |
@@ -14,2 +14,8 @@ /** | ||
* against `example: {}` or `example: []`. | ||
* | ||
* It is also used elsewhere throughout rttc. | ||
* | ||
* @param {Anything} val | ||
* @param {Boolean?} allowNull | ||
* @param {Boolean?} dontStringifyFunctions | ||
*/ | ||
@@ -16,0 +22,0 @@ module.exports = function rebuildSanitized(val, allowNull, dontStringifyFunctions) { |
@@ -7,3 +7,2 @@ /** | ||
var _ = require('lodash'); | ||
var rebuildSanitized = require('./sanitize'); | ||
@@ -10,0 +9,0 @@ |
@@ -94,3 +94,3 @@ /** | ||
// If the actual value is undefined, fill in with the | ||
// appropriate base type. | ||
// appropriate base value for the type. | ||
if(_.isUndefined(actual)) { | ||
@@ -97,0 +97,0 @@ coercedValue = expectedType.getBase(); |
155
lib/infer.js
@@ -7,128 +7,51 @@ /** | ||
var types = require('./helpers/types'); | ||
var inferPrimitive = require('./helpers/infer-primitive'); | ||
/** | ||
* Given a primitive exemplar, return its type. | ||
* ________________________________________________________________________________ | ||
* @param {*} eg there's that "mystery meat" again | ||
* ________________________________________________________________________________ | ||
* @returns {String} | ||
* Infer the type schema of the provided RTTC exemplar (aka example). | ||
* | ||
* @param {JSON} eg [an rttc exemplar] | ||
* @return {JSON} [a type schema] | ||
*/ | ||
module.exports = function infer(eg) { | ||
function getTypeOfPrimitive(eg) { | ||
// Check for `type: 'ref'` (===) | ||
if (types.ref.isExemplar(eg)) { | ||
return 'ref'; | ||
// If the exemplar isn't a dictionary or array, we will infer | ||
// its type without messing around with any kind of recursion. | ||
if(!types.dictionary.is(eg) && !types.array.is(eg)) { | ||
return inferPrimitive(eg); | ||
} | ||
// Check for `type: 'lamda'` (->) | ||
if (types.lamda.isExemplar(eg)) { | ||
return 'lamda'; | ||
} | ||
// Check for `type: 'json'` (*) | ||
if (types.json.isExemplar(eg)){ | ||
return 'json'; | ||
} | ||
// Check for string | ||
if (types.string.isExemplar(eg)) { | ||
return 'string'; | ||
} | ||
// Check for number | ||
if (types.number.isExemplar(eg)) { | ||
return 'number'; | ||
} | ||
// Check for boolean | ||
if (types.boolean.isExemplar(eg)) { | ||
return 'boolean'; | ||
} | ||
// This return value of undefined means the inference failed. | ||
return; | ||
} | ||
/** | ||
* Recursively create a new type schema dictionary from an exemplar. | ||
* ________________________________________________________________________________ | ||
* @param {Object} obj | ||
* ________________________________________________________________________________ | ||
* @returns {Object} If this is an object, returns a new schema object. | ||
* @returns {undefined} If `obj` is not an object | ||
*/ | ||
function getSchemaOfObject(obj) { | ||
if(!types.dictionary.is(obj)) return; | ||
var newObj = {}; | ||
_.each(_.keys(obj), function(key) { | ||
var val = obj[key]; | ||
var type; | ||
if(types.array.is(val)) { | ||
type = infer(val); | ||
// If the exemplar is an array... | ||
else if(types.array.is(eg)) { | ||
// If this array is empty, that means it's a generic array exemplar. | ||
// (we do not parse generic array exemplars recursively.) | ||
if (eg.length === 0) { | ||
return eg; | ||
} | ||
else if(types.dictionary.is(val)) { | ||
type = getSchemaOfObject(val); | ||
} | ||
// Otherwise this is pattern array- which we do infer recursively. | ||
else { | ||
type = getTypeOfPrimitive(val); | ||
} | ||
newObj[key] = type; | ||
}); | ||
return newObj; | ||
} | ||
/** | ||
* Given an exemplar, parse it to infer its type schema. | ||
* ________________________________________________________________________________ | ||
* @param {*} eg | ||
* ________________________________________________________________________________ | ||
* @returns {*} a type schema | ||
*/ | ||
function infer(eg) { | ||
// If the exemplar isn't a dictionary or array, we will derive its primitive type. | ||
if(!types.dictionary.is(eg) && !types.array.is(eg)) { | ||
return getTypeOfPrimitive(eg); | ||
// << Recursive step >> | ||
return [ infer(eg[0]) ]; | ||
}//</pattern array> | ||
} | ||
// If the exemplar is a dictionary... | ||
else { | ||
// If this dictionary is empty, that means it's a generic | ||
// dictionary exemplar (we do not parse generic dictionary | ||
// exemplars recursively.) | ||
if (_.keys(eg).length === 0) { | ||
return eg; | ||
}//</generic dictionary> | ||
// If the exemplar is an array, figure out what to do. | ||
// For now just check that it's an array. | ||
if(types.array.is(eg)) { | ||
// Ensure empty arrays are not recursively parsed. | ||
if (eg.length === 0) { | ||
return []; | ||
} | ||
// Parse arrays of arrays | ||
if (_.isArray(eg[0])) { | ||
return [infer(eg[0])]; | ||
} | ||
// Parse arrays of objects | ||
if (_.isObject(eg[0])) { | ||
return [getSchemaOfObject(eg[0])]; | ||
} | ||
// Parse arrays of primitives | ||
return [getTypeOfPrimitive(eg[0])]; | ||
// Otherwise, this is a faceted dictionary exemplar. | ||
// So we infer its type schema recursively. | ||
else { | ||
var dictionaryTypeSchema = {}; | ||
_.each(_.keys(eg), function(key) { | ||
// << Recursive step >> | ||
dictionaryTypeSchema[key] = infer(eg[key]); | ||
}); | ||
return dictionaryTypeSchema; | ||
}//</faceted dictionary> | ||
} | ||
// Otherwise parse the object | ||
return getSchemaOfObject(eg); | ||
} | ||
module.exports = infer; | ||
}; |
@@ -22,3 +22,2 @@ /** | ||
// If typeSchema is not provided, use `_.isEqual` | ||
// TODO: make this better | ||
if (_.isUndefined(typeSchema)) { | ||
@@ -28,103 +27,94 @@ return _.isEqual(firstValue, secondValue); | ||
// console.log('\n\n\n'); | ||
// console.log('running equality check:'); | ||
// console.log(firstValue); | ||
// console.log('vs:'); | ||
// console.log(secondValue); | ||
// console.log(); | ||
// Otherwise recursively crawl the type schema and ensure that `firstValue` | ||
// and `secondValue` are equivalent to one another in all the places. | ||
return _isEqualRecursive(firstValue, secondValue, typeSchema, []); | ||
// | ||
// The following code returns the result via calling a self-calling | ||
// (but *named*) recursive function. | ||
}; | ||
/** | ||
* [_isEqualRecursive description] | ||
* @param {[type]} firstValue [description] | ||
* @param {[type]} secondValue [description] | ||
* @param {[type]} typeSchema [description] | ||
* @param {[type]} keypathArray [description] | ||
* @param {[type]} keyOrIndex [description] | ||
* @return {Boolean} [description] | ||
*/ | ||
return (function _isEqualRecursive(firstValue, secondValue, typeSchema, keypathArray, keyOrIndex){ | ||
try { | ||
// console.log(' ('+keypathArray.join('.')+') \n•',firstValue,'vs', secondValue); | ||
/** | ||
* [_isEqualRecursive description] | ||
* @param {[type]} firstValue [description] | ||
* @param {[type]} secondValue [description] | ||
* @param {[type]} typeSchema [description] | ||
* @param {[type]} keypathArray [description] | ||
* @param {[type]} keyOrIndex [description] | ||
* @return {Boolean} [description] | ||
*/ | ||
function _isEqualRecursive(firstValue, secondValue, typeSchema, keypathArray, keyOrIndex){ | ||
try { | ||
// console.log(' ('+keypathArray.join('.')+') \n•',firstValue,'vs', secondValue); | ||
// Attempt to look up the appropriate keypath within the type schema, or | ||
// use the top-level type schema if we haven't tracked any key/indices traversed | ||
// yet. | ||
var typeToCompareAgainst; | ||
if (keypathArray.length === 0) { | ||
typeToCompareAgainst = typeSchema; | ||
} | ||
else { | ||
var lastTypeToCompareAgainst = _.get(typeSchema, keypathArray.slice(0,-1).join('.')); | ||
// If previous comparison type was a homogenous array type (i.e. any array at this point) | ||
// ensure that we use the first item of the type schema as our type-- because otherwise | ||
// it won't exist! | ||
if (_.isArray(lastTypeToCompareAgainst)) { | ||
typeToCompareAgainst = _.get(typeSchema, keypathArray.slice(0,-1).concat([0]).join('.')); | ||
// Attempt to look up the appropriate keypath within the type schema, or | ||
// use the top-level type schema if we haven't tracked any key/indices traversed | ||
// yet. | ||
var typeToCompareAgainst; | ||
if (keypathArray.length === 0) { | ||
typeToCompareAgainst = typeSchema; | ||
} | ||
// Otherwise, just grab the type to compare against normally: | ||
else { | ||
typeToCompareAgainst = _.get(typeSchema, keypathArray.join('.')); | ||
var lastTypeToCompareAgainst = _.get(typeSchema, keypathArray.slice(0,-1).join('.')); | ||
// If previous comparison type was a homogenous array type (i.e. any array at this point) | ||
// ensure that we use the first item of the type schema as our type-- because otherwise | ||
// it won't exist! | ||
if (_.isArray(lastTypeToCompareAgainst)) { | ||
typeToCompareAgainst = _.get(typeSchema, keypathArray.slice(0,-1).concat([0]).join('.')); | ||
} | ||
// Otherwise, just grab the type to compare against normally: | ||
else { | ||
typeToCompareAgainst = _.get(typeSchema, keypathArray.join('.')); | ||
} | ||
} | ||
} | ||
// Also look up the two value segments we'll be comparing below | ||
var firstValueSegment = keypathArray.length === 0 ? firstValue : _.get(firstValue, keypathArray.join('.')); | ||
var secondValueSegment = keypathArray.length === 0 ? secondValue : _.get(secondValue, keypathArray.join('.')); | ||
// Also look up the two value segments we'll be comparing below | ||
var firstValueSegment = keypathArray.length === 0 ? firstValue : _.get(firstValue, keypathArray.join('.')); | ||
var secondValueSegment = keypathArray.length === 0 ? secondValue : _.get(secondValue, keypathArray.join('.')); | ||
// Keep track of indices/keys already traversed in order to dereference the appropriate part | ||
// of the type schema (`indexOrKey` will be undefined if this is the top-level) | ||
keypathArray.push(keyOrIndex); | ||
// Keep track of indices/keys already traversed in order to dereference the appropriate part | ||
// of the type schema (`indexOrKey` will be undefined if this is the top-level) | ||
keypathArray.push(keyOrIndex); | ||
if (_.isArray(typeToCompareAgainst)) { | ||
if (_.isEqual(typeToCompareAgainst, [])){ | ||
return _.isEqual(firstValueSegment, secondValueSegment); | ||
if (_.isArray(typeToCompareAgainst)) { | ||
if (_.isEqual(typeToCompareAgainst, [])){ | ||
return _.isEqual(firstValueSegment, secondValueSegment); | ||
} | ||
// Only take the recursive step for homogeneous arrays | ||
return _.all(firstValueSegment, function checkEachItemIn1stArray(unused, i){ | ||
return _isEqualRecursive(firstValue, secondValue, typeSchema, keypathArray, i); | ||
}) && | ||
_.all(secondValueSegment, function checkEachItemIn2ndArray(unused, i){ | ||
return _isEqualRecursive(firstValue, secondValue, typeSchema, keypathArray, i); | ||
}); | ||
} | ||
// Only take the recursive step for homogeneous arrays | ||
return _.all(firstValueSegment, function checkEachItemIn1stArray(unused, i){ | ||
return _isEqualRecursive(firstValue, secondValue, typeSchema, keypathArray, i); | ||
}) && | ||
_.all(secondValueSegment, function checkEachItemIn2ndArray(unused, i){ | ||
return _isEqualRecursive(firstValue, secondValue, typeSchema, keypathArray, i); | ||
}); | ||
} | ||
else if (_.isObject(typeToCompareAgainst)) { | ||
if (_.isEqual(typeToCompareAgainst, {})){ | ||
else if (_.isObject(typeToCompareAgainst)) { | ||
if (_.isEqual(typeToCompareAgainst, {})){ | ||
return _.isEqual(firstValueSegment, secondValueSegment); | ||
} | ||
// Only take the recursive step for faceted arrays | ||
return _.all(firstValueSegment, function checkEachItemIn1stDict(unused, key){ | ||
return _isEqualRecursive(firstValue, secondValue, typeSchema, keypathArray, key); | ||
}) && | ||
_.all(secondValueSegment, function checkEachItemIn2ndDict(unused, key){ | ||
return _isEqualRecursive(firstValue, secondValue, typeSchema, keypathArray, key); | ||
}); | ||
} | ||
// If this type is a lamda, `.toString()` the functions and compare | ||
// them that way. | ||
else if (typeToCompareAgainst === 'lamda') { | ||
// console.log('Comparing lamdas...'); | ||
return (firstValueSegment.toString() === secondValueSegment.toString()); | ||
} | ||
else { | ||
// console.log('not lamda, its:', typeToCompareAgainst); | ||
return _.isEqual(firstValueSegment, secondValueSegment); | ||
} | ||
// Only take the recursive step for faceted arrays | ||
return _.all(firstValueSegment, function checkEachItemIn1stDict(unused, key){ | ||
return _isEqualRecursive(firstValue, secondValue, typeSchema, keypathArray, key); | ||
}) && | ||
_.all(secondValueSegment, function checkEachItemIn2ndDict(unused, key){ | ||
return _isEqualRecursive(firstValue, secondValue, typeSchema, keypathArray, key); | ||
}); | ||
} | ||
// If this type is a lamda, `.toString()` the functions and compare | ||
// them that way. | ||
else if (typeToCompareAgainst === 'lamda') { | ||
// console.log('Comparing lamdas...'); | ||
return (firstValueSegment.toString() === secondValueSegment.toString()); | ||
catch (e){ | ||
// console.log('------ ERR ------',e.stack); | ||
return false; | ||
} | ||
else { | ||
// console.log('not lamda, its:', typeToCompareAgainst); | ||
return _.isEqual(firstValueSegment, secondValueSegment); | ||
} | ||
} | ||
catch (e){ | ||
// console.log('------ ERR ------',e.stack); | ||
return false; | ||
} | ||
} | ||
})(firstValue, secondValue, typeSchema, []);//</self-calling recursive fn> | ||
}; |
@@ -5,4 +5,2 @@ /** | ||
var util = require('util'); | ||
var _ = require('lodash'); | ||
var validateRecursive = require('./helpers/validate-recursive'); | ||
@@ -20,5 +18,2 @@ var consolidateErrors = require('./helpers/consolidate-errors'); | ||
// Avoid damaging `expected` | ||
expected = _.cloneDeep(expected); | ||
var errors = []; | ||
@@ -31,5 +26,7 @@ var result = validateRecursive(expected, actual, errors, [], true); | ||
var err = consolidateErrors(errors, 'validating value'); | ||
if (err) throw err; | ||
if (err) { | ||
throw err; | ||
} | ||
}; | ||
@@ -5,4 +5,2 @@ /** | ||
var util = require('util'); | ||
var _ = require('lodash'); | ||
var validateRecursive = require('./helpers/validate-recursive'); | ||
@@ -24,6 +22,2 @@ var consolidateErrors = require('./helpers/consolidate-errors'); | ||
// Avoid damaging `expected` | ||
expected = _.cloneDeep(expected); | ||
// TODO: add sufficient tests to ensure this is never a problem, then remove this to improve performance. | ||
var errors = []; | ||
@@ -36,6 +30,9 @@ var result = validateRecursive(expected, actual, errors, [], false); | ||
var err = consolidateErrors(errors, 'validating value'); | ||
if (err) throw err; | ||
else return result; | ||
if (err) { | ||
throw err; | ||
} else { | ||
return result; | ||
} | ||
}; | ||
{ | ||
"name": "rttc", | ||
"version": "9.3.1", | ||
"version": "9.3.2", | ||
"description": "Runtime type-checking for JavaScript.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
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
220199
43
4700