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 0.2.2 to 0.2.3

lib/helpers/validate-recursive.js

94

lib/coerce.js

@@ -7,6 +7,5 @@ /**

var _ = require('lodash');
var types = require('./types');
var validateRecursive = require('./helpers/validate-recursive');
/**

@@ -27,5 +26,9 @@ * Coerce value to type schema

var errors = [];
var result = _coerceRecursive(expected, actual, errors);
var result = validateRecursive(expected, actual, errors);
// Strip out "E_INVALID_TYPE" errors- they are ok if we're just coercing.
_.remove(errors, {code: 'E_INVALID_TYPE'});
if (errors.length) {
throw (function (){

@@ -41,86 +44,1 @@ var err = new Error(util.format('%d error(s) coercing value:\n', errors.length, errors));

};
function _coerceRecursive (expected, actual, errors){
// Look up expected type from `types` object using `expected`.
var expectedType;
var isExpectingArray;
var isExpectingDictionary;
// Arrays
if (_.isArray(expected)) {
expectedType = types.arr;
isExpectingArray = true;
}
// Dictionaries
else if (_.isObject(expected)) {
expectedType = types.obj;
isExpectingDictionary = true;
}
// Primitives
else {
expectedType = types[expected];
// If this refers to an unknown type, default
// to a string's base type and remember the error.
if (_.isUndefined(expectedType)) {
errors.push((function (){
var err = new Error('Unknown type: '+expected);
err.code = 'E_UNKNOWN_TYPE';
return err;
})());
return types.string.getBase();
}
}
// Default the coercedValue to the actual value.
var coercedValue = actual;
// If the actual value is undefined, fill in with the
// appropriate base type.
if(types.undefined.is(actual)) {
coercedValue = expectedType.getBase();
}
// Check `actual` value against expectedType
if (!expectedType.is(actual)){
// Invalid expected type. Try to coerce:
try {
coercedValue = expectedType.to(actual);
}
catch (e) {
// If that doesn't work, use the base type:
coercedValue = expectedType.getBase();
// Saving this error here in case we need it:
// (but turning it off for now because this function
// is very forgiving and kind)
// errors.push((function (){
// var err = new Error(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)
// ));
// err.code = 'E_INVALID_TYPE';
// return err;
// })());
}
}
// Build partial result
// (taking recursive step if necessary)
if (isExpectingArray) {
var arrayItemTpl = expected[0];
return [_coerceRecursive(arrayItemTpl, coercedValue[0], errors)];
}
if (isExpectingDictionary) {
return _.reduce(expected, function (memo, expectedVal, expectedKey) {
memo[expectedKey] = _coerceRecursive(expected[expectedKey], coercedValue[expectedKey], errors);
return memo;
}, {});
}
return coercedValue;
}

@@ -13,2 +13,5 @@ /**

// Backwards compat.
/**

@@ -15,0 +18,0 @@ * Given a definition and a values object, ensure our types match up.

@@ -5,10 +5,37 @@ /**

var util = require('util');
var _ = require('lodash');
var rttc = require('./rttc');
var validateRecursive = require('./helpers/validate-recursive');
/**
* Validate a bit of mystery meat (`actual`) against an `expected` type schema,
* saving up any fatal errors and throwing them in a lump, and otherwise
* returning the value that was accepted (i.e. because some coercion might have
* occurred)
*
* @param {~Schema} expected type schema
* @param {*} actual "mystery meat"
* @return {<expected>}
*/
module.exports = function validate (expected, actual) {
module.exports = function validate (expected, actual) {
// TODO: make this the top-level method instead of rttc
// and share common fn dependencies
return rttc(expected, actual);
// Avoid damaging the provided parameters.
expected = _.cloneDeep(expected);
actual = _.cloneDeep(actual);
var errors = [];
var result = validateRecursive(expected, actual, 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;
err.errors = errors;
return err;
})();
}
return result;
};
{
"name": "rttc",
"version": "0.2.2",
"version": "0.2.3",
"description": "Runtime type-checking for JavaScript.",

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

# rttc
Runtime type-checking for JavaScript.
Runtime (recursive) type-checking for JavaScript.

@@ -10,6 +10,10 @@ ## Installation

```js
var rttc = require('rttc');
```
## Rules
## Philosophy
#### General

@@ -22,37 +26,54 @@

#### Coercion vs. Validation
+ `.validate()` either returns a (potentially "lightly" coerced) version of the value that was accepted, or it throws. The "lightly" coerced value might turn `"3"` into `3`, `"true"` into `true`, `-4.5` into `"-4.5"`, etc.
+ `.coerce()` ALWAYS returns an acceptable version of the value, even if it has to mangle it to get there.
## Legacy Usage
#### Dictionaries
The usage of this module is changing, but backwards compatibility will be maintained up until the first major version bump (v1.0.0).
See tests for more details.
+ Dictionaries (i.e. plain old JavaScript objects) in type schemas can be infinitely nested. Type validation and coercion will proceed through the nested objects recursively.
#### rttc.rttc(expectations, inputValues, [options])
```js
{
id: 'number',
name: 'string',
isAdmin: 'boolean',
mom: {
id: 'number',
name: 'string',
occupation: {
title: 'string',
workplace: 'string'
}
}
}
```
Validate and/or coerce a set of input values against a set of expectations (defined as input definitions.)
#### Arrays
Two options may be provided:
+ `coerce` - before failing, attempt to coerce not-quite-right input values to their expected type.
+ `base` - if an input value is missing, fill in its place in the result to the "base type" (falsy value)
+ Arrays in type schemas must be homogeneous and have exactly one item; that is, if you want to validate an array, you only need to provide the type/schema for the first item in the array, e.g.:
```js
require('rttc').rttc({
foo: {
type: 'string',
required: true
},
bar: {
type: { baz: {name: 'string'} },
required: false
[
{
id: 'number',
name: 'string',
email: 'string',
age: 'number',
isAdmin: 'boolean',
favoriteColors: ['string'],
friends: [
{
id: 'number',
name: 'string'
}
]
}
}, {
foo: 'hi',
bar: {
baz: {
name: 'Rick'
}
}
});
]
```
## Usage
#### rttc.infer(value)

@@ -115,2 +136,152 @@

#### `.validate(expected, actual)`
```js
rttc.validate('string', 'foo');
// => 'foo'
rttc.validate('number', 4.5);
// => 4.5
rttc.validate('boolean', true);
// => true
rttc.validate('string', -2);
// => '-2'
rttc.validate('string', false);
// => 'false'
rttc.validate('number', '3');
// => 3
rttc.validate('boolean', 'true');
// => true
rttc.validate({
user: {
friends: [{
name: 'Lenny',
age: 77
}]
}, {
user: {
friends: [{
name: 'Lenny',
age: '77'
}]
}
});
// =>
/*
{
user: {
friends: [{
name: 'Lenny',
age: 77
}]
}
}
*/
```
If value cannot be properly coerced, throws error with code=`E_INVALID_TYPE`:
```js
rttc.validate('number', 'asdf');
// throws E_INVALID_TYPE
```
#### `.coerce(expected, actual)`
```js
rttc.coerce('string', 'foo');
// => 'foo'
rttc.coerce('number', 4.5);
// => 4.5
rttc.coerce('boolean', true);
// => true
rttc.coerce('string', -2);
// => '-2'
rttc.coerce('string', false);
// => 'false'
rttc.coerce('number', '3');
// => 3
rttc.coerce('boolean', 'true');
// => true
```
If value cannot be properly coerced, defaults to base type:
```
rttc.coerce('number', 'asdf');
// => 0
rttc.coerce('boolean', 'asdf');
// => false
rttc.coerce({
user: {
friends: [{
name: 'Lenny',
age: 77
}]
}, 'err... some dude who\'s friends with lenny?');
// =>
/*
{
user: {
friends: [{
name: 'Lenny',
age: 77
}]
}
}
*/
```
## Legacy Usage
The usage of this module is changing, but backwards compatibility will be maintained up until the first major version bump (v1.0.0).
See tests for more details.
#### rttc.rttc(expectations, inputValues, [options])
Validate and/or coerce a set of input values against a set of expectations (defined as input definitions.)
Two options may be provided:
+ `coerce` - before failing, attempt to coerce not-quite-right input values to their expected type.
+ `base` - if an input value is missing, fill in its place in the result to the "base type" (falsy value)
```js
require('rttc').rttc({
foo: {
type: 'string',
required: true
},
bar: {
type: { baz: {name: 'string'} },
required: false
}
}, {
foo: 'hi',
bar: {
baz: {
name: 'Rick'
}
}
});
```
#### rttc.types

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