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 6.0.0 to 7.0.0

221

lib/helpers/sanitize.js

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

// 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`.
// Then build a deep copy
// (in the process, remove keys with undefined values from nested dictionaries recursively)
return _recursivelyRebuildAndSanitize(val, allowNull);
// 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.
return _rebuild(val, allowNull);
};

@@ -76,92 +57,156 @@

function _recursivelyRebuildAndSanitize (val, allowNull) {
if (_.isArray(val)) {
return _.reduce(val,function (memo, item, i) {
if (!_.isUndefined(item) && (allowNull || !_.isNull(item))) {
memo.push(_recursivelyRebuildAndSanitize(item, allowNull));
}
return memo;
}, []);
}
else if (_.isObject(val)) {
return _.reduce(val,function (memo, subVal, key) {
if (!_.isUndefined(subVal) && (allowNull || !_.isNull(subVal))) {
memo[key] = _recursivelyRebuildAndSanitize(subVal, allowNull);
}
return memo;
}, {});
}
else {
return val;
}
}
/**
* This was modified by @mikermcneil from @isaacs' json-stringify-safe
* (see https://github.com/isaacs/json-stringify-safe/commit/02cfafd45f06d076ac4bf0dd28be6738a07a72f9#diff-c3fcfbed30e93682746088e2ce1a4a24)
* @param {===} val [description]
* @return {String} [description]
*/
function stringifySafe(val) {
return JSON.stringify(val, serializer());
}
function serializer(replacer, cycleReplacer) {
function _rebuild(val, allowNull) {
var stack = [];
var keys = [];
if (!cycleReplacer) {
cycleReplacer = function(key, value) {
// if (!cycleReplacer) {
var cycleReplacer = function(unused, value) {
if (stack[0] === value) return '[Circular ~]';
return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
};
}
// }
return function(key, value) {
function _recursivelyRebuildAndSanitize (val, key) {
// Handle circle jerks
if (stack.length > 0) {
var thisPos = stack.indexOf(this);
~thisPos ? stack.splice(thisPos + 1) : stack.push(this);
var self = this;
var thisPos = stack.indexOf(self);
~thisPos ? stack.splice(thisPos + 1) : stack.push(self);
~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key);
if (~stack.indexOf(value)) value = cycleReplacer.call(this, key, value);
if (~stack.indexOf(val)) {
val = cycleReplacer.call(self, key, val);
}
}
else stack.push(value);
else stack.push(val);
// Rebuild and strip undefineds/nulls
if (_.isArray(val)) {
return _.reduce(val,function (memo, item, i) {
if (!_.isUndefined(item) && (allowNull || !_.isNull(item))) {
memo.push(_recursivelyRebuildAndSanitize.call(val, item, i));
}
return memo;
}, []);
}
// Serialize errors, regexps, dates, and functions to strings:
if (_.isError(value)){
value = value.stack;
else if (_.isError(val)){
val = val.stack;
}
else if (_.isRegExp(value)){
value = value.toString();
else if (_.isRegExp(val)){
val = val.toString();
}
else if (_.isFunction(value)){
value = value.toString();
else if (_.isDate(val)){
val = val.toJSON();
}
else if (_.isObject(value)){
if (value instanceof Readable) {
else if (_.isFunction(val)){
val = val.toString();
}
else if (!_.isObject(val)) {
// Coerce NaN, Infinity, and -Infinity to 0:
if (_.isNaN(val)) {
val = 0;
}
else if (val === Infinity) {
val = 0;
}
else if (val === -Infinity) {
val = 0;
}
}
else if (_.isObject(val)) {
if (val instanceof Readable) {
return null;
}
if (value instanceof Buffer) {
if (val instanceof Buffer) {
return null;
}
return _.reduce(val,function (memo, subVal, key) {
if (!_.isUndefined(subVal) && (allowNull || !_.isNull(subVal))) {
memo[key] = _recursivelyRebuildAndSanitize.call(val, subVal, key);
}
return memo;
}, {});
}
// Coerce NaN, Infinity, and -Infinity to 0:
if (_.isNaN(value)) {
value = 0;
}
else if (value === Infinity) {
value = 0;
}
else if (value === -Infinity) {
value = 0;
}
if (!replacer) {
return value;
}
return replacer.call(this, key, value);
};
return val;
}
// Pass in the empty string to satisfy Mr. isaac's replacer
return _recursivelyRebuildAndSanitize(val, '');
}
// /**
// * This was modified by @mikermcneil from @isaacs' json-stringify-safe
// * (see https://github.com/isaacs/json-stringify-safe/commit/02cfafd45f06d076ac4bf0dd28be6738a07a72f9#diff-c3fcfbed30e93682746088e2ce1a4a24)
// * @param {===} val [description]
// * @return {String} [description]
// */
// function stringifySafe(val) {
// return JSON.stringify(val, serializer());
// }
// function serializer(replacer, cycleReplacer) {
// var stack = [];
// var keys = [];
// if (!cycleReplacer) {
// cycleReplacer = function(key, value) {
// if (stack[0] === value) return '[Circular ~]';
// return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
// };
// }
// return function(key, value) {
// if (stack.length > 0) {
// var thisPos = stack.indexOf(this);
// ~thisPos ? stack.splice(thisPos + 1) : stack.push(this);
// ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key);
// if (~stack.indexOf(value)) value = cycleReplacer.call(this, key, value);
// }
// else stack.push(value);
// // Serialize errors, regexps, dates, and functions to strings:
// if (_.isError(value)){
// value = value.stack;
// }
// else if (_.isRegExp(value)){
// value = value.toString();
// }
// else if (_.isFunction(value)){
// value = value.toString();
// }
// else if (_.isObject(value)){
// if (value instanceof Readable) {
// return null;
// }
// if (value instanceof Buffer) {
// return null;
// }
// }
// // Coerce NaN, Infinity, and -Infinity to 0:
// if (_.isNaN(value)) {
// value = 0;
// }
// else if (value === Infinity) {
// value = 0;
// }
// else if (value === -Infinity) {
// value = 0;
// }
// if (!replacer) {
// return value;
// }
// return replacer.call(this, key, value);
// };
// }

@@ -185,3 +185,3 @@ /**

// ...expecting ANY json-compatible value (`"%json"`)
// ...expecting ANY json-compatible value (`"*"`)
if (allowAnyJSONCompatible) {

@@ -196,3 +196,3 @@ // (run rebuildSanitized with `allowNull` enabled)

if (allowAnyArray) {
return rebuildSanitized(coercedValue);
return rebuildSanitized(coercedValue, true);
}

@@ -203,2 +203,7 @@

return _.reduce(coercedValue, function (memo, coercedVal){
// Never consider `undefined` a real array item. Because things cannot be and also not be.
if (_.isUndefined(coercedVal)) {
return memo;
}
memo.push(_validateRecursive(arrayItemTpl, coercedVal, errors, ensureSerializable, undefined, strict));

@@ -213,3 +218,3 @@ return memo;

if (allowAnyDictionary){
return rebuildSanitized(coercedValue);
return rebuildSanitized(coercedValue, true);
}

@@ -216,0 +221,0 @@ // ...expecting a specific dictionary example

{
"name": "rttc",
"version": "6.0.0",
"version": "7.0.0",
"description": "Runtime type-checking for JavaScript.",

@@ -5,0 +5,0 @@ "main": "index.js",

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

| undefined | `undefined` | `null` |
| [undefined] | `[undefined]` | [] |
| {foo: undefined} | `{foo: undefined}` | {} |
| Infinity | `Infinity` | `0` |

@@ -262,8 +264,10 @@ | -Infinity | `-Infinity` | `0` |

+ are guaranteed to be JSON-serializable, with a few additional affordances:
+ normally, stringified JSON may contain `null` values. Instead, rttc removes `null` items from arrays and removes keys with `null` values from objects.
+ normally, `Error` instances get stringified into empty objects. Instead, rttc turns them into human-readable strings by reducing them to their `.stack` property (this includes the error message and the stack trace w/ line numbers)
+ normally, `RegExp` instances get stringified into empty objects. Instead, rttc turns them into human-readable strings like `'/some regexp/gi'`
+ normally, `function()` instances get stringified into empty objects. Instead, rttc turns them into human-readable strings like `'function doStuff (a,b) { console.log(\'wow I can actually read this!\'); }'`
+ keys with undefined values at any level will be stripped out
+ undefined items in nested arrays will be stripped out
+ keys with null values may be present
+ null items in nested arrays may be present
#### Faceted dictionaries

@@ -302,6 +306,9 @@

+ are guaranteed to be JSON-serializable, with a few additional affordances:
+ normally, stringified JSON may contain `null` values. Instead, rttc removes `null` items from arrays and removes keys with `null` values from objects.
+ normally, `Error` instances get stringified into empty objects. Instead, rttc turns them into human-readable strings by reducing them to their `.stack` property (this includes the error message and the stack trace w/ line numbers)
+ normally, `RegExp` instances get stringified into empty objects. Instead, rttc turns them into human-readable strings like `'/some regexp/gi'`
+ normally, `function()` instances get stringified into empty objects. Instead, rttc turns them into human-readable strings like `'function doStuff (a,b) { console.log(\'wow I can actually read this!\'); }'`
+ keys of nested dictionaries with undefined values will be stripped out
+ undefined array items at any level will be stripped out
+ keys of nested dictionaries with null values may be present
+ null items in arrays at any level may be present

@@ -323,2 +330,4 @@

Undefined items will always be stripped out of arrays.
> Also note that, because of this, when providing a type schema or type-inference-able example for an array, you only need to provide one item in the array, e.g.:

@@ -349,3 +358,3 @@

This works pretty much like the generic array or generic dictionary type, with two major differences: (1) the top-level value can be a string, boolean, number, dictionary, array, or null value. (2) `null` is permitted, both as a top-level value and recursively in nested arrays and dictionaries (and as you might expect, `null` values are NOT stripped from nested arrays and dictionaries when performing type coercion)
This works pretty much like the generic array or generic dictionary type, with one major difference: the top-level value can be a string, boolean, number, dictionary, array, or null value.

@@ -360,3 +369,3 @@ Other than the aforementioned exception for `null`, the generic JSON type follows the JSON-serializability rules from generic arrays and generic dictionaries.

This special type allows anything except `undefined`. It also _does not rebuild objects_, which means it maintains the original reference (i.e. is `===`). It does not guarantee JSON-serializability.
This special type allows anything except `undefined` at the top level (undefined is permitted at any other level). It also _does not rebuild objects_, which means it maintains the original reference (i.e. is `===`). It does not guarantee JSON-serializability.

@@ -390,3 +399,3 @@

+ `undefined` IS, however, allowed as an item in a nested array or value in a nested dictionary, but only against the mutable reference type (`===`)
+ `null` is only valid against the JSON (`*`) and mutable reference (`===`) types.
+ `null` is only valid at the top level against the JSON (`*`) and mutable reference (`===`) types.

@@ -393,0 +402,0 @@ ##### Weird psuedo-numeric values

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

{ example: {}, actual: { x: -Infinity }, result: { x: 0 } },
{ example: {}, actual: { x: null }, result: {} },
{ example: {}, actual: { x: null }, result: { x:null } },
{ example: {}, actual: { x: function foo(a,b){return a+' '+b;} }, result: { x: 'function foo(a,b){return a+\' \'+b;}' } },

@@ -269,3 +269,3 @@ // { example: {}, actual: { x: undefined, null, NaN, -Infinity, Infinity, function(){} }, result: [] },

{ example: [], actual: [undefined], result: [] },
{ example: [], actual: [null], result: [] },
{ example: [], actual: [null], result: [null] },
{ example: [], actual: [NaN], result: [0] },

@@ -272,0 +272,0 @@ { example: [], actual: [Infinity], result: [0] },

@@ -75,8 +75,10 @@ /**

// test one level of additional array nesting
recursiveTests.push({
example: [ customCloneDeep(test.example) ],
actual: [ customCloneDeep(test.actual) ],
result: [ customCloneDeep(test.result) ],
_meta: '+1 array depth'
});
if (!_.isUndefined(test.actual)) {
recursiveTests.push({
example: [ customCloneDeep(test.example) ],
actual: [ customCloneDeep(test.actual) ],
result: [ customCloneDeep(test.result) ],
_meta: '+1 array depth'
});
}

@@ -107,9 +109,11 @@ // test one level of additional dictionary nesting

// test two levels of additional array nesting
recursiveTests.push({
example: [ [ customCloneDeep(test.example) ] ],
actual: [ [ customCloneDeep(test.actual) ] ],
result: [ [ customCloneDeep(test.result) ] ],
_meta: '+2 array depth'
});
if (!_.isUndefined(test.actual)) {
// test two levels of additional array nesting
recursiveTests.push({
example: [ [ customCloneDeep(test.example) ] ],
actual: [ [ customCloneDeep(test.actual) ] ],
result: [ [ customCloneDeep(test.result) ] ],
_meta: '+2 array depth'
});
}

@@ -125,16 +129,20 @@ // test two levels of additional dictionary nesting AND 1 level of array nesting

// test two levels of additional dictionary nesting and one level of array nesting, then WITHIN that, 1 level of array nesting
recursiveTests.push({
example: [ { xtra: { xtra2: [customCloneDeep(test.example)] } } ],
actual: [ { xtra: { xtra2: [customCloneDeep(test.actual)] } } ],
result: [ { xtra:{ xtra2: [customCloneDeep(test.result)] } } ],
_meta: '+1 array depth, +2 dictionary depth, +1 nested array depth'
});
if (!_.isUndefined(test.actual)) {
recursiveTests.push({
example: [ { xtra: { xtra2: [customCloneDeep(test.example)] } } ],
actual: [ { xtra: { xtra2: [customCloneDeep(test.actual)] } } ],
result: [ { xtra:{ xtra2: [customCloneDeep(test.result)] } } ],
_meta: '+1 array depth, +2 dictionary depth, +1 nested array depth'
});
}
// test two levels of additional dictionary nesting and one level of array nesting, then WITHIN that, 2 levels of array nesting
recursiveTests.push({
example: [ { xtra: { xtra2: [[customCloneDeep(test.example)]] } } ],
actual: [ { xtra: { xtra2: [[customCloneDeep(test.actual)]] } } ],
result: [ { xtra:{ xtra2: [[customCloneDeep(test.result)]] } } ],
_meta: '+1 array depth, +2 dictionary depth, +2 nested array depth'
});
if (!_.isUndefined(test.actual)) {
// test two levels of additional dictionary nesting and one level of array nesting, then WITHIN that, 2 levels of array nesting
recursiveTests.push({
example: [ { xtra: { xtra2: [[customCloneDeep(test.example)]] } } ],
actual: [ { xtra: { xtra2: [[customCloneDeep(test.actual)]] } } ],
result: [ { xtra:{ xtra2: [[customCloneDeep(test.result)]] } } ],
_meta: '+1 array depth, +2 dictionary depth, +2 nested array depth'
});
}
}

@@ -141,0 +149,0 @@

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

{ example: {}, actual: { x: -Infinity }, result: {x:0} },
{ example: {}, actual: { x: null }, result: {} },
{ example: {}, actual: { x: null }, result: {x: null} },
{ example: {}, actual: { x: function foo(a,b){return a+' '+b;} }, result: { x: 'function foo(a,b){return a+\' \'+b;}' } },

@@ -267,3 +267,3 @@ // { example: {}, actual: { x: undefined, null, NaN, -Infinity, Infinity, function(){} }, result: [] },

{ example: [], actual: [undefined], result: [] },
{ example: [], actual: [null], result: [] },
{ example: [], actual: [null], result: [null] },
{ example: [], actual: [NaN], result: [0] },

@@ -572,3 +572,3 @@ { example: [], actual: [Infinity], result: [0] },

actual: [{a:3}, undefined, {a: 5}, undefined, {a: 7}, {a:9, b: [undefined, 9,2,4,undefined,8]}],
error: true
result: [{a:3}, {a: 5}, {a: 7}, {a:9, b: [undefined, 9,2,4,undefined,8]}]
},

@@ -575,0 +575,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