Socket
Socket
Sign inDemoInstall

rttc

Package Overview
Dependencies
Maintainers
4
Versions
108
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rttc - npm Package Compare versions

Comparing version 1.0.2 to 2.0.1

lib/helpers/consolidate-errors.js

1

index.js
module.exports = {
validate: require('./lib/validate'),
validateStrict: require('./lib/validate-strict'),
coerce: require('./lib/coerce'),
infer: require('./lib/infer')
};

21

lib/coerce.js

@@ -8,2 +8,3 @@ /**

var validateRecursive = require('./helpers/validate-recursive');
var consolidateErrors = require('./helpers/consolidate-errors');

@@ -27,2 +28,3 @@ /**

var result = validateRecursive(expected, actual, errors, true);
// (the true => `ensureSerializable` -- i.e. ensure the thingĀ is JSON-serializable)

@@ -35,13 +37,12 @@ // Strip out "E_INVALID_TYPE" errors- they are ok if we're just coercing.

if (errors.length) {
// TODO:
// Note that it would be more efficient to pass in a list of error codes
// to ignore when calling `validateRecursive`, rather than iterating through
// the list of errors afterwards and stripping them out.
throw (function (){
var err = new Error(util.format('%d error(s) coercing value:\n', errors.length, errors));
err.code = errors[0].code;
err.errors = errors;
return err;
})();
}
return result;
// If there are still errors, coallesce the remaining list of errors into a single
// Error object we can throw.
var err = consolidateErrors(errors, 'coercing value');
if (err) throw err;
else return result;
};

@@ -25,3 +25,2 @@ /**

to: function(v) {
if (_.isUndefined(v)){ return false; }
if(_.isBoolean(v)) return v;

@@ -51,13 +50,10 @@ if (_.isNumber(v)){

if (_.isUndefined(v)){
return '';
}
if(_.isString(v)) return v;
if(v instanceof Function) {
throw new Error('E_runtimeInputTypeCoercionError');
// Convert date into zone-independent (UTC) ISO-8601 timestamp
if(_.isDate(v)) {
return v.toJSON();
}
if(_.isDate(v)) {
if (_.isUndefined(v)){
throw new Error('E_runtimeInputTypeCoercionError');

@@ -119,3 +115,15 @@ }

}
// Don't tolerate regexps or dates.
if (_.isDate(v) || _.isRegExp(v)) {
throw new Error('E_runtimeInputTypeCoercionError');
}
// But otherwise, if this is NOT a "plain object", determine whether
// it's JSON-compatible and if so, coerce it to that.
try {
return JSON.parse(JSON.stringify(v));
}
catch (e) {}
// If that doesn't work, give up
throw new Error('E_runtimeInputTypeCoercionError');

@@ -143,3 +151,3 @@ },

// Nuber
// Number
number: {

@@ -151,19 +159,9 @@ is: function(v) {

if (_.isUndefined(v)){
return 0;
}
// Check for Infinity and NaN
if(v === Infinity || v === -Infinity) {
throw new Error('E_runtimeInputTypeCoercionError');
}
if (_.isNaN(v)) {
throw new Error('E_runtimeInputTypeCoercionError');
}
if (_.isNull(v)){
throw new Error('E_runtimeInputTypeCoercionError');
}
if (v === Infinity || v === -Infinity) throw new Error('E_runtimeInputTypeCoercionError');
if (_.isNaN(v)) throw new Error('E_runtimeInputTypeCoercionError');
if (_.isNull(v)) throw new Error('E_runtimeInputTypeCoercionError');
if (_.isUndefined(v)) throw new Error('E_runtimeInputTypeCoercionError');
if (_.isObject(v)) throw new Error('E_runtimeInputTypeCoercionError');
if (_.isObject(v)) return 0;
if(type.number.is(v)) return v;

@@ -192,3 +190,2 @@ if(type.boolean.is(v)) return v ? 1 : 0;

// Check for Infinity

@@ -202,3 +199,2 @@ if (v === 'Infinity' || v === '-Infinity') {

var num = v * 1;

@@ -208,9 +204,3 @@ if(!_.isNumber(num)) {

}
if (_.isNaN(num)) {
return 0;
}
return (num === 0 && !v.match(/^0+$/)) ? 0 : num;
},

@@ -217,0 +207,0 @@ getBase: function (){

@@ -20,3 +20,3 @@ /**

*/
module.exports = function _validateRecursive (expected, actual, errors, ensureSerializable, meta){
module.exports = function _validateRecursive (expected, actual, errors, ensureSerializable, meta, strict){

@@ -31,3 +31,3 @@ // Look up expected type from `types` object using `expected`.

// console.log('\n');
// console.log('expecting:',expected, util.format('(a %s)', getDisplayType(actual)));
// console.log('expecting:',expected);
// console.log('actual:',require('util').inspect(actual, false, null), require('util').format('(a %s)', getDisplayType(actual)));

@@ -46,8 +46,7 @@ function getDisplayType(x){

if (expected === '*'){
// TODO: reconsider this-- might be confusing... probably better just to pass through `undefined`
return _.isUndefined(actual) ? '' : actual;
return actual;
}
// Normalize: ["*"] or [] or "array" (allow any array)
if (expected === 'array' || (_.isArray(expected) && (expected[0] === '*' || expected.length === 0))) {
// Normalize: [] or ['*'] or "array" (allow any array)
if (expected === 'array' || (_.isArray(expected) && (expected.length === 0 || expected[0] === '*'))) {
expected = ['*'];

@@ -62,3 +61,2 @@ allowAnyArray = true;

// Arrays

@@ -90,62 +88,77 @@ if (_.isArray(expected)) {

// console.log('expected = %s || actual = %s (%s)',expected, actual, typeof actual);
// Ensure that `actual` is JSON-serializable, unless one of the following is true:
// - the `ensureSerializable` flag is disabled
// - we're expecting a "machine", "buffer", or "stream" and the mystery meat looks right enough
//
// Notes:
// + this can be disabled by setting the `ensureSerializable` argument to false (i.e. for performance)
// + this will strip all functions
// + cloning buffers breaks them-- also it is potentially a huge waste of RAM)
// + cloning streams is a bad idea because it disregards the state they're in, event listeners, etc.)
if (ensureSerializable &&
expected !== 'machine' &&
expected !== 'buffer' &&
expected !== 'stream'
) {
// // For most actual values, we want to ensure it is pseudo-JSON-serializable.
// // We say "pseudo" because we would rather not allow `null` for now,
// // which is technically allowed in JSON. TODO: expand this comment to reflect reality
// //
// //
// // So specifically, we'll ensure that `actual` is pseudo-JSON-serializable,
// // unless one of the following is true:
// // - the `ensureSerializable` flag is disabled
// // - we're expecting a "machine", "buffer", or "stream" and the mystery meat looks right enough
// //
// // Notes:
// // + this can be disabled by setting the `ensureSerializable` argument to false (i.e. for performance)
// // + this will strip all functions
// // + cloning buffers breaks them-- also it is potentially a huge waste of RAM)
// // + cloning streams is a bad idea because it disregards the state they're in, event listeners, etc.)
// if (ensureSerializable &&
// expected !== 'machine' &&
// expected !== 'buffer' &&
// expected !== 'stream'
// ) {
// if (
// // If we're not expecting a buffer, but it looks like we got one, don't serialize it to JSON and back
// // (it will end up looking like an array, which is confusing)
// // !(expected !== 'buffer' && _.isObject(actual) && actual instanceof Buffer)
// // console.log('ensuring actual value is serializable as JSON...');
// ) {
try {
actual = JSON.parse(JSON.stringify(actual));
}
catch (e){
// Push an E_INVALID_TYPE error
errors.push((function (){
var msg = util.format(
'An invalid value was specified: \n' + util.inspect(actual, false, null) + '\n\n' +
'This doesn\'t match the specified type: \n' + util.inspect(expected, false, null)
);
if (meta && meta.keyName) {
msg = "For key `"+meta.keyName+"`: " + msg;
}
var err = new Error(msg);
if (meta && meta.keyName) {
err.inputKey = meta.keyName;
}
err.actual = util.inspect(actual, false, null);
err.expected = util.inspect(expected, false, null);
err.code = 'E_INVALID_TYPE';
// // Formerly we did this: (but not anymore)
// // ================================================================
// // If we're not expecting a buffer, but it looks like we got one actually,
// // don't serialize it to JSON and back.
// // (it will end up looking like an array, which is confusing)
// // !(expected !== 'buffer' && _.isObject(actual) && actual instanceof Buffer)
// // ================================================================
// try {
// actual = JSON.parse(JSON.stringify(actual));
// }
// catch (e){
// // Build an E_INVALID_TYPE error
// var newErr = (function (){
// var msg = util.format(
// 'An invalid value was specified: \n' + util.inspect(actual, false, null) + '\n\n' +
// 'This doesn\'t match the specified type: \n' + util.inspect(expected, false, null)
// );
// if (meta && meta.keyName) {
// msg = "For key `"+meta.keyName+"`: " + msg;
// }
// var err = new Error(msg);
// if (meta && meta.keyName) {
// err.inputKey = meta.keyName;
// }
// err.actual = util.inspect(actual, false, null);
// err.expected = util.inspect(expected, false, null);
// err.code = 'E_INVALID_TYPE';
// if not expecting a dictionary or an array, and actual value is not
// a dictionary or array, then this is just a "minor" thing.
// No big deal, you know.
if (!isExpectingDictionary && !isExpectingArray && !_.isObject(actual)) {
err.minor = true;
}
return err;
})());
actual = {};
}
// }
}
// TODO: probably should clone machine defs as well.
// // if not expecting a dictionary or an array, and actual value is not
// // a dictionary or array, then this is just a "minor" thing.
// // No big deal, you know.
// if (!isExpectingDictionary && !isExpectingArray && !_.isObject(actual)) {
// err.minor = true;
// }
// return err;
// })();
// // Don't bother tracking minor errors unless we're in `strict` mode.
// if (!newErr.minor || (strict && newErr.minor)) {
// errors.push(newErr);
// }
// actual = {};
// }
// }
// // TODO: probably should clone machine defs as well.
// // console.log('(4) actual =',actual);
// Default the coercedValue to the actual value.

@@ -162,6 +175,6 @@ var coercedValue = actual;

if (!expectedType.is(actual)){
// console.log('.is() failed!');
// Push an E_INVALID_TYPE error
errors.push((function (){
// Build an E_INVALID_TYPE error
var newErr = (function (){
var msg = util.format(

@@ -172,3 +185,3 @@ 'An invalid value was specified: \n' + util.inspect(actual, false, null) + '\n\n' +

if (meta && meta.keyName) {
msg = "For key `"+meta.keyName+"`: " + msg;
msg = 'For key `'+meta.keyName+'`: ' + msg;
}

@@ -183,11 +196,17 @@ var err = new Error(msg);

// if not expecting a dictionary or an array, and actual value is not
// a dictionary or array, then this is just a "minor" thing.
// No big deal, you know.
if (!isExpectingDictionary && !isExpectingArray && !_.isObject(actual)) {
// This is considered a "minor" error if it can be coerced without
// causing any errors.
try {
expectedType.to(actual);
err.minor = true;
}
catch (e) {}
return err;
})());
})();
// Don't bother tracking minor errors unless we're in `strict` mode.
if (!newErr.minor || (strict && newErr.minor)) {
errors.push(newErr);
}
// Invalid expected type. Try to coerce:

@@ -209,3 +228,3 @@ try {

if (meta && meta.keyName) {
msg = "For key `"+meta.keyName+"`: " + msg;
msg = 'For key `'+meta.keyName+'`: ' + msg;
}

@@ -224,13 +243,2 @@ var err = new Error(msg);

// console.log('coercedValue:',util.inspect(coercedValue, false, null), util.format('(a %s)', (function(){
// var displayType;
// displayType = typeof coercedValue;
// try {
// displayType = coercedValue.constructor.name;
// }
// catch (e){}
// return displayType;
// })()));
// Build partial result

@@ -244,3 +252,3 @@ // (taking recursive step if necessary)

return _.reduce(coercedValue, function (memo, coercedVal){
memo.push(_validateRecursive(arrayItemTpl, coercedVal, errors, ensureSerializable));
memo.push(_validateRecursive(arrayItemTpl, coercedVal, errors, ensureSerializable, undefined, strict));
return memo;

@@ -254,4 +262,4 @@ }, []);

return _.reduce(expected, function (memo, expectedVal, expectedKey) {
var keyName = (meta && meta.keyName ? (meta.keyName + ".") : "") + expectedKey;
memo[expectedKey] = _validateRecursive(expected[expectedKey], coercedValue[expectedKey], errors, ensureSerializable, {keyName: keyName});
var keyName = (meta && meta.keyName ? (meta.keyName + '.') : '') + expectedKey;
memo[expectedKey] = _validateRecursive(expected[expectedKey], coercedValue[expectedKey], errors, ensureSerializable, {keyName: keyName}, strict);
return memo;

@@ -258,0 +266,0 @@ }, {});

@@ -31,2 +31,7 @@ /**

// Infer type:'*' if `'*'` or `undefined` is provided
if (val === '*' || val === undefined) {
type = '*';
}
return type;

@@ -94,6 +99,2 @@ }

}
// Handle special case of [*]
else if (example.length === 1 && example[0] === '*') {
return [];
}

@@ -100,0 +101,0 @@ // Parse arrays of arrays

@@ -8,3 +8,5 @@ /**

var validateRecursive = require('./helpers/validate-recursive');
var consolidateErrors = require('./helpers/consolidate-errors');
/**

@@ -22,27 +24,17 @@ * Validate a bit of mystery meat (`actual`) against an `expected` type schema,

// Avoid damaging the provided parameters.
// Avoid damaging `expected`
expected = _.cloneDeep(expected);
var errors = [];
var result = validateRecursive(expected, actual, errors, true);
var result = validateRecursive(expected, actual, errors, true, undefined, false);
// (the `true` => `ensureSerializable` -- i.e. ensure the thingĀ is JSON-serializable, if possible)
// (the `false` => `strict` -- i.e. ignore minor type errors)
if (errors.length) {
throw (function (){
var err = new Error(util.format('%d error(s) validating value:\n', errors.length, errors));
err.code = errors[0].code;
// If any of the errors are not "minor", then this is not a "minor" error.
err.minor = _.reduce(errors, function(memo, subError) {
if (!memo || !subError.minor) {
return false;
}
return true;
}, true);
err.errors = errors;
return err;
})();
}
return result;
// If there are still errors, coallesce the remaining list of errors into a single
// Error object we can throw.
var err = consolidateErrors(errors, 'validating value');
if (err) throw err;
else return result;
};
{
"name": "rttc",
"version": "1.0.2",
"version": "2.0.1",
"description": "Runtime type-checking for JavaScript.",
"main": "index.js",
"scripts": {
"test": "node ./node_modules/mocha/bin/mocha --recursive"
"test": "node ./node_modules/mocha/bin/mocha --recursive -R dot"
},

@@ -9,0 +9,0 @@ "keywords": [

@@ -31,2 +31,4 @@ # rttc

<!--

@@ -67,2 +69,5 @@ TODO:

When validating against a dictionary schema with at least one key, extra keys in the actual value will be stripped out. If the dictionary schema is empty, all actual keys will be left alone.
#### Arrays

@@ -69,0 +74,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with āš”ļø by Socket Inc