Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

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 3.0.0 to 3.0.1

19

lib/helpers/types.js

@@ -221,19 +221,16 @@ /**

// Don't tolerate non-objects, or arrays, or regexps, or dates.
if (!_.isObject(v) || _.isArray(v) || _.isDate(v) || _.isRegExp(v)) {
if (!_.isObject(v) || _.isArray(v) || _.isDate(v) || _.isRegExp(v) || _.isError(v)) {
throw new Error('E_runtimeInputTypeCoercionError');
}
// Plain objects are ok, but we'll clone them.
// (TODO: this should be configurable)
// Plain objects are ok, pass them on through
//
// (we used to clone them here, but it's not actually necessary, since we
// rebuild those which have explicit nested `example`s, and if this is
// `example: {}`, we're rebuilding the dictionary and all of its contents
// recursively anyways as the last step in `validate-recursive`.)
if (_.isPlainObject(v)){
return _.clone(v);
return v;
}
// If this is NOT a "plain object" (i.e. some kind of prototypal thing)
// 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

@@ -240,0 +237,0 @@ throw new Error('E_runtimeInputTypeCoercionError');

@@ -179,3 +179,3 @@ /**

if (allowAnyArray) {
return recursivelyCloneAndStripUndefinedKeysFromDictionaries(coercedValue);
return rebuildSanitized(coercedValue);
}

@@ -195,3 +195,3 @@

if (allowAnyDictionary){
return recursivelyCloneAndStripUndefinedKeysFromDictionaries(coercedValue);
return rebuildSanitized(coercedValue);
}

@@ -216,77 +216,79 @@ // ...expecting a specific dictionary example

/**
*
* Rebuild a value to make it JSON-compatible (plus some extra affordances)
* This is used when validating/coercing an array or dictionary (and its contents)
* against `example: {}` or `example: []`.
*/
function recursivelyCloneAndStripUndefinedKeysFromDictionaries(val) {
function rebuildSanitized(val) {
// (note that the recursive validation will not penetrate deeper into this
// object, so we don't have to worry about this function running more than once
// and doing unnecessary extra deep copies at each successive level)
// First, prevent against endless circular recursion:
// (this should never throw, but if it does, it needs to be handled
// by the caller of `rebuildSanitized`)
val = JSON.parse(stringifySafe(val));
// So doing that parse/stringify thing will remove keys that have undefined values on its own.
// BUT, we still have to worry about removing array items which are undefined.
// And the above operation actually converts these undefined items into `null` items.
// But since we aren't really OK with `null` items either, we can just go ahead and strip
// them out. So we do that in `_recursivelyRebuildAndSanitize`.
// If dictionary:
// ==============================================================================
// Sanitize a dictionary provided for a wildcard dictionary example (`example: {}`)
// The main recursive validation function will not descend into this dictionary because
// it's already met the minimum requirement of being an object. So we need to deep clone
// the provided value for safety; and in the process ensure that it meets the basic minimum
// quality requirements (i.e. no dictionaries within have any undefined keys)
//
// At this point, we can be sure that the provided value is a plain object
// (otherwise it would have been caught by the coercion step, since in order to
// be considered a "dictionary", a value has to pass a _.isPlainObject() check)
// Then build a deep copy
// (in the process, remove keys with undefined values from nested dictionaries recursively)
return _recursivelyRebuildAndSanitize(val);
// TODO:
// could consolidate this cloning + stripping undefined keys + prevention against
// ∞-recursion into a single tree traversal, which would triple the efficiency,
// because then instead of doing "stringify", then "parse", then "rebuild", it could
// all be accomplished in just one iteration instead of three.
}
// If array:
// ==============================================================================
// Sanitize an array provided for a wildcard array example (`example: []`)
// The main recursive validation function will not descend into this array because
// it's already met the minimum requirement of being `_.isArray()`. So we need to
// deep clone the provided value for safety; and in the process ensure that it meets
// the basic minimum quality requirements (i.e. no dictionaries within have any undefined
// keys)
//
// (NOTE: `example: ['*']` won't make it here because it will be picked up
// by the recursive validation. And so it's different-- it will contain
// the original items, and therefore may contain dictionaries w/ undefined keys)
//
// At this point, we can be sure that the provided value is an array
// (otherwise it would have been caught by the coercion step, since in order to
// be considered an "array", a value has to pass a _.isArray() check)
// (note that the recursive validation will not penetrate deeper into this
// object, so we don't have to worry about this function running more than once
// and doing unnecessary extra deep copies at each successive level)
function _recursivelyCloneAndStripUndefinedKeys (val) {
if (_.isArray(val)) {
return _.reduce(val,function (memo, item, i) {
memo.push(_recursivelyCloneAndStripUndefinedKeys(item));
return memo;
}, []);
}
else if (_.isObject(val)) {
return _.reduce(val,function (memo, subVal, key) {
if (!_.isUndefined(subVal)) {
memo[key] = _recursivelyCloneAndStripUndefinedKeys(subVal);
}
return memo;
}, {});
}
else {
return val;
}
}
// If dictionary:
// ==============================================================================
// Sanitize a dictionary provided for a wildcard dictionary example (`example: {}`)
// The main recursive validation function will not descend into this dictionary because
// it's already met the minimum requirement of being an object. So we need to deep clone
// the provided value for safety; and in the process ensure that it meets the basic minimum
// quality requirements (i.e. no dictionaries within have any keys w/ invalid values)
// If array:
// ==============================================================================
// Sanitize an array provided for a wildcard array example (`example: []`)
// The main recursive validation function will not descend into this array because
// it's already met the minimum requirement of being `_.isArray()`. So we need to
// deep clone the provided value for safety; and in the process ensure that it meets
// the basic minimum quality requirements (i.e. no dictionaries within have any keys w/
// invalid values)
//
// We also don't include invalid items in the rebuilt array.
//
// (NOTE: `example: ['*']` won't make it here because it will be picked up
// by the recursive validation. And so it's different-- it will contain
// the original items, and therefore may contain dictionaries w/ keys w/ invalid values)
function _recursivelyRebuildAndSanitize (val) {
if (_.isArray(val)) {
return _.reduce(val,function (memo, item, i) {
if (!_.isUndefined(item) && !_.isNull(item)) {
memo.push(_recursivelyRebuildAndSanitize(item));
}
return memo;
}, []);
}
// First, prevent against endless circular recursion:
// (this should never throw, but if it does, it needs to be handled
// by the caller of `recursivelyCloneAndStripUndefinedKeysFromDictionaries`)
val = JSON.parse(stringifySafe(val));
// TODO:
// could consolidate this cloning + stripping undefined keys + prevention against
// ∞-recursion into a single tree traversal, which would double the efficiency.
// Then build a deep copy
// (in the process, remove keys with undefined values from nested dictionaries recursively)
return _recursivelyCloneAndStripUndefinedKeys(val);
else if (_.isObject(val)) {
return _.reduce(val,function (memo, subVal, key) {
if (!_.isUndefined(subVal) && !_.isNull(subVal)) {
memo[key] = _recursivelyRebuildAndSanitize(subVal);
}
return memo;
}, {});
}
else {
return val;
}
}

@@ -296,3 +298,2 @@

/**

@@ -328,2 +329,16 @@ * This was modified by @mikermcneil from @isaacs' json-stringify-safe

// Do some advanced serialization
if (_.isError(value)){
value = value.stack;
}
else if (_.isRegExp(value)){
value = value.toString();
}
else if (_.isFunction(value)){
value = value.toString();
}
else if (_.isArray(value)) {
}
if (!replacer) {

@@ -330,0 +345,0 @@ return value;

{
"name": "rttc",
"version": "3.0.0",
"version": "3.0.1",
"description": "Runtime type-checking for JavaScript.",

@@ -32,3 +32,3 @@ "main": "index.js",

"dependencies": {
"lodash": "~2.4.1"
"lodash": "^3.8.0"
},

@@ -35,0 +35,0 @@ "devDependencies": {

@@ -62,12 +62,14 @@ # rttc

+ For "stream", base value is an empty readable buffer stream (i.e. not in object mode)
+ For "machine", base value is a no-op machine that calls its success exit.
-->
#### Edge cases
+ `undefined` is never valid.
+ `null` is never valid.
+ `NaN` is never valid.
+ `Infinity` is never valid.
+ `-Infinity` is never valid.
+ `null` is only valid against `example: '*'`.
+ `NaN` is only valid against `example: '*'`.
+ `Infinity` is only valid against `example: '*'`.
+ `-Infinity` is only valid against `example: '*'`.

@@ -74,0 +76,0 @@

@@ -145,3 +145,3 @@ // Export the array of tests below.

////////////////////////////////////////////
// DICTIONARIES
// DICTIONARIES (json-serializable)
////////////////////////////////////////////

@@ -187,6 +187,6 @@

////////////////////////////////////////////
// ARRAYS
// (all of the tests below pass w/ either [] or ['*']
// however note they do have subtle differences re: strictEq)
// ARRAYS (json-serializable)
// (all of the tests below pass w/ [], not necessarily ['*'])
////////////////////////////////////////////

@@ -228,3 +228,52 @@

//////////////////////////////////////////////////////
// nested contents of `example: []` and `example: {}`
//////////////////////////////////////////////////////
// Follow JSON-serialization rules for nested objects within `example: []` and `example: {}`
// with the following exceptions:
// • convert Error instances to their `.stack` property (a string)
// • convert RegExp instances to a string
// • convert functions to a string
// • after doing the rest of the things, prune undefined/null items
// • after doing the rest of the things, strip keys w/ undefined/null values
{ example: {}, actual: { x: undefined }, result: {} },
{ example: {}, actual: { x: NaN }, result: {} },
{ example: {}, actual: { x: Infinity }, result: {} },
{ example: {}, actual: { x: -Infinity }, result: {} },
{ example: {}, actual: { x: null }, result: {} },
{ example: {}, actual: { x: function foo(a,b){return a+' '+b;} }, result: { x: 'function foo(a,b){return a+\' \'+b;}' } },
// { example: {}, actual: { x: undefined, null, NaN, -Infinity, Infinity, function(){} }, result: [] },
{ example: {}, actual: { x: /some regexp/ig }, result: {x:'/some regexp/gi' }},
{ example: {}, actual: { x: new Date('November 5, 1605 GMT') }, result: {x: '1605-11-05T00:00:00.000Z'} },
// Skip Readable stream tests for now since the enumerable properties vary between Node.js versions.
// { example: {}, actual: { x: new (require('stream').Readable)() }, result: { x: { _readableState: {},readable: true,_events: {},_maxListeners: 10 } } },
// Skip Buffer stream tests for now since the enumerable properties vary between Node.js versions.
// { example: {}, actual: { x: new Buffer('asdf') } , result: {x: {}} },
(function (){
// Hard-code a fake `.stack` to avoid differences between computers that would cause tests to fail
var e = new Error('asdf');
e.stack = 'fake_error';
return { example: {}, actual: { x: e }, result: {x:'fake_error'} };
})(),
{ example: [], actual: [undefined], result: [] },
{ example: [], actual: [null], result: [] },
{ example: [], actual: [NaN], result: [] },
{ example: [], actual: [Infinity], result: [] },
{ example: [], actual: [-Infinity], result: [] },
{ example: [], actual: [function foo(a,b){return a+' '+b;}], result: ['function foo(a,b){return a+\' \'+b;}'] },
{ example: [], actual: [/some regexp/gi], result: ['/some regexp/gi'] },
{ example: [], actual: [new Date('November 5, 1605 GMT')], result: ['1605-11-05T00:00:00.000Z'] },
// Skip Readable stream tests for now since the enumerable properties vary between Node.js versions.
// { example: [], actual: [new (require('stream').Readable)()], result: [ { _readableState: {},readable: true,_events: {},_maxListeners: 10 }] },
// Skip Buffer stream tests for now since the enumerable properties vary between Node.js versions.
// { example: [], actual: [new Buffer('asdf')], result: [{}] },
(function (){
var e = new Error('asdf');
e.stack = 'fake_error';
return { example: [], actual: [e], result: ['fake_error'] };
})(),
////////////////////////////////////////////

@@ -275,3 +324,3 @@ // example: * (aka undefined)

{ example: undefined, actual: /some regexp/, result: /some regexp/ },
{ example: undefined, actual: /some regexp/gi, result: /some regexp/gi },
{ example: undefined, actual: new Date('November 5, 1605 GMT'), result: new Date('November 5, 1605 GMT') },

@@ -358,2 +407,24 @@

// Leave `undefined` items from arrays and nested arrays alone (`*` case)
{
example: '*',
actual: [{a:3}, undefined, {a: 5}, undefined, {a: 7}, {a:9, b: [undefined, 9,2,4,undefined,8]}],
result: [{a:3}, undefined, {a: 5}, undefined, {a: 7}, {a:9, b: [undefined, 9,2,4,undefined,8]}]
},
// Leave `undefined` items from arrays and nested arrays (`[*]` case)
// (because '*' leaves them there)
{
example: ['*'],
actual: [{a:3}, undefined, {a: 5}, undefined, {a: 7}, {a:9, b: [undefined, 9,2,4,undefined,8]}],
result: [{a:3}, undefined, {a: 5}, undefined, {a: 7}, {a:9, b: [undefined, 9,2,4,undefined,8]}]
},
// Prune `undefined` items from arrays and nested arrays (`[]` case)
{
example: [],
actual: [{a:3}, undefined, {a: 5}, undefined, {a: 7}, {a:9, b: [undefined, 9,2,4,undefined,8]}],
result: [{a: 3}, {a: 5}, {a:7}, {a:9, b:[9,2,4,8]}]
},
// Ensure that nested dictionaries inside of an array passed

@@ -360,0 +431,0 @@ // through `example: ['*']` are NOT stripped of keys with undefined values--

@@ -149,3 +149,3 @@ // Export the array of tests below

////////////////////////////////////////////
// DICTIONARIES
// DICTIONARIES (json-serializable)
////////////////////////////////////////////

@@ -192,9 +192,8 @@

{ example: {}, actual: new Error('asdf'), result: {} }, // TODO: consider enhancing this behavior to guarantee e.g. `.message` (string), `.stack` (string), `.code` (string), and `.status` (number). Needs community discussion
{ example: {}, actual: new Error('asdf'), error: true },
////////////////////////////////////////////
// ARRAYS
// (all of the tests below pass w/ either [] or ['*']
// however note they do have subtle differences re: strictEq)
// ARRAYS (json-serializable)
// (all of the tests below pass w/ [], not necessarily ['*'])
////////////////////////////////////////////

@@ -237,2 +236,54 @@

//////////////////////////////////////////////////////
// nested contents of `example: []` and `example: {}`
//////////////////////////////////////////////////////
// Follow JSON-serialization rules for nested objects within `example: []` and `example: {}`
// with the following exceptions:
// • convert Error instances to their `.stack` property (a string)
// • convert RegExp instances to a string
// • convert functions to a string
// • after doing the rest of the things, prune undefined/null items
// • after doing the rest of the things, strip keys w/ undefined/null values
{ example: {}, actual: { x: undefined }, result: {} },
{ example: {}, actual: { x: NaN }, result: {} },
{ example: {}, actual: { x: Infinity }, result: {} },
{ example: {}, actual: { x: -Infinity }, result: {} },
{ example: {}, actual: { x: null }, result: {} },
{ example: {}, actual: { x: function foo(a,b){return a+' '+b;} }, result: { x: 'function foo(a,b){return a+\' \'+b;}' } },
// { example: {}, actual: { x: undefined, null, NaN, -Infinity, Infinity, function(){} }, result: [] },
{ example: {}, actual: { x: /some regexp/ig }, result: {x:'/some regexp/gi' }},
{ example: {}, actual: { x: new Date('November 5, 1605 GMT') }, result: {x: '1605-11-05T00:00:00.000Z'} },
// Skip Readable stream tests for now since the enumerable properties vary between Node.js versions.
// { example: {}, actual: { x: new (require('stream').Readable)() }, result: { x: { _readableState: {},readable: true,_events: {},_maxListeners: 10 } } },
// Skip Buffer stream tests for now since the enumerable properties vary between Node.js versions.
// { example: {}, actual: { x: new Buffer('asdf') } , result: {x: {}} },
(function (){
// Hard-code a fake `.stack` to avoid differences between computers that would cause tests to fail
var e = new Error('asdf');
e.stack = 'fake_error';
return { example: {}, actual: { x: e }, result: {x:'fake_error'} };
})(),
{ example: [], actual: [undefined], result: [] },
{ example: [], actual: [null], result: [] },
{ example: [], actual: [NaN], result: [] },
{ example: [], actual: [Infinity], result: [] },
{ example: [], actual: [-Infinity], result: [] },
{ example: [], actual: [function foo(a,b){return a+' '+b;}], result: ['function foo(a,b){return a+\' \'+b;}'] },
{ example: [], actual: [/some regexp/gi], result: ['/some regexp/gi'] },
{ example: [], actual: [new Date('November 5, 1605 GMT')], result: ['1605-11-05T00:00:00.000Z'] },
// Skip Readable stream tests for now since the enumerable properties vary between Node.js versions.
// { example: [], actual: [new (require('stream').Readable)()], result: [ { _readableState: {},readable: true,_events: {},_maxListeners: 10 }] },
// Skip Buffer stream tests for now since the enumerable properties vary between Node.js versions.
// { example: [], actual: [new Buffer('asdf')], result: [{}] },
(function (){
var e = new Error('asdf');
e.stack = 'fake_error';
return { example: [], actual: [e], result: ['fake_error'] };
})(),
////////////////////////////////////////////

@@ -393,2 +444,24 @@ // RECURSIVE OBJECTS

// Prune `undefined` items from arrays and nested arrays (`[]` case)
{
example: [],
actual: [{a:3}, undefined, {a: 5}, undefined, {a: 7}, {a:9, b: [undefined, 9,2,4,undefined,8]}],
result: [{a: 3}, {a: 5}, {a:7}, {a:9, b:[9,2,4,8]}]
},
// DO allow `undefined` items from arrays and nested arrays (`*` case)
{
example: '*',
actual: [{a:3}, undefined, {a: 5}, undefined, {a: 7}, {a:9, b: [undefined, 9,2,4,undefined,8]}],
result: [{a:3}, undefined, {a: 5}, undefined, {a: 7}, {a:9, b: [undefined, 9,2,4,undefined,8]}]
},
// Don't allow `undefined` items from arrays and nested arrays (`[*]` case)
// (because '*' does not allow `undefined`)
{
example: ['*'],
actual: [{a:3}, undefined, {a: 5}, undefined, {a: 7}, {a:9, b: [undefined, 9,2,4,undefined,8]}],
error: true
},
// Ensure that nested dictionaries inside of an array passed

@@ -395,0 +468,0 @@ // through `example: ['*']` are NOT stripped of keys with undefined values--

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