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

blork

Package Overview
Dependencies
Maintainers
1
Versions
56
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

blork - npm Package Compare versions

Comparing version 3.4.1 to 3.5.0

lib/constants.js

154

lib/check.js
const BlorkError = require("./BlorkError");
const format = require("./format");
const { ANY } = require("./constants");

@@ -10,4 +11,4 @@ /**

* @param {string} name Name of the value (prefixed to error messages to assist debugging).
* @param {Error} instanceError Type of error that gets thrown if values don't match types.
* @param {Object} instanceCheckers An object listing checkers for a Blork isntance.
* @param {Error} err Type of error that gets thrown if values don't match types.
* @param {Object} checkers An object listing checkers for a Blork isntance.
*

@@ -19,5 +20,5 @@ * @return {integer} Returns the number of values that passed their checks.

*/
function check(value, type, name, instanceError, instanceCheckers) {
function check(value, type, name, err, checkers) {
// Defer to internal check, setting a blank typeStack and valueStack.
return checkInternal(value, type, name, instanceError, instanceCheckers, [], []);
return checkInternal(value, type, name, err, checkers, [], []);
}

@@ -31,4 +32,4 @@

* @param {string} name Name of the value (prefixed to error messages to assist debugging).
* @param {Error} instanceError Type of error that gets thrown if values don't match types.
* @param {Object} instanceCheckers An object listing checkers for a Blork isntance.
* @param {Error} err Type of error that gets thrown if values don't match types.
* @param {Object} checkers An object listing checkers for a Blork isntance.
* @param {Array} typeStack The stack of parent types to track infinite loops.

@@ -42,10 +43,12 @@ * @param {Array} valueStack The stack of parent values to track infinite loops.

*/
function checkInternal(value, type, name, instanceError, instanceCheckers, typeStack, valueStack) {
function checkInternal(value, type, name, err, checkers, typeStack, valueStack) {
// Found.
if (typeof type === "string") return checkString(value, type, name, instanceError, instanceCheckers);
else if (type instanceof Function) return checkFunction(value, type, name, instanceError, instanceCheckers);
else if (type instanceof Array)
return checkArray(value, type, name, instanceError, instanceCheckers, typeStack, valueStack);
else if (type instanceof Object)
return checkObject(value, type, name, instanceError, instanceCheckers, typeStack, valueStack);
if (typeof type === "string") return checkString(value, type, name, err, checkers);
else if (type === true) return checkString(value, "true", name, err, checkers);
else if (type === false) return checkString(value, "false", name, err, checkers);
else if (type === null) return checkString(value, "null", name, err, checkers);
else if (type === undefined) return checkString(value, "undefined", name, err, checkers);
else if (type instanceof Function) return checkFunction(value, type, name, err, checkers);
else if (type instanceof Array) return checkArray(value, type, name, err, checkers, typeStack, valueStack);
else if (type instanceof Object) return checkObject(value, type, name, err, checkers, typeStack, valueStack);

@@ -62,4 +65,4 @@ // Not found.

* @param {string} name Name of the value (prefixed to error messages to assist debugging).
* @param {Error} instanceError Type of error that gets thrown if values don't match types.
* @param {Object} instanceCheckers An object listing checkers for a Blork isntance.
* @param {Error} err Type of error that gets thrown if values don't match types.
* @param {Object} checkers An object listing checkers for a Blork isntance.
*

@@ -71,5 +74,5 @@ * @return {integer} Returns the number of values that passed their checks.

*/
function checkString(value, type, name, instanceError, instanceCheckers) {
function checkString(value, type, name, err, checkers) {
// Find checker in list of checkers.
let checker = instanceCheckers[type];
let checker = checkers[type];

@@ -81,3 +84,3 @@ // Checker didn't exist.

// Find checker without '?'.
checker = instanceCheckers[type.slice(0, -1)];
checker = checkers[type.slice(0, -1)];

@@ -96,3 +99,3 @@ // Undefined.

// Error if it returned string.
if (typeof result === "string") throw new instanceError(format(result, value, name));
if (typeof result === "string") throw new err(format(result, value, name));

@@ -109,4 +112,4 @@ // Success if it returned anything else.

* @param {string} name Name of the value (prefixed to error messages to assist debugging).
* @param {Error} instanceError Type of error that gets thrown if values don't match types.
* @param {Object} instanceCheckers An object listing checkers for a Blork isntance.
* @param {Error} err Type of error that gets thrown if values don't match types.
* @param {Object} checkers An object listing checkers for a Blork isntance.
*

@@ -118,3 +121,3 @@ * @return {integer} Returns the number of values that passed their checks.

*/
function checkFunction(value, type, name, instanceError, instanceCheckers) {
function checkFunction(value, type, name, err, checkers) {
// Vars.

@@ -127,9 +130,9 @@ let result = true;

case Boolean:
result = instanceCheckers.bool(value);
result = checkers.bool(value);
break;
case Number:
result = instanceCheckers.num(value);
result = checkers.num(value);
break;
case String:
result = instanceCheckers.str(value);
result = checkers.str(value);
break;

@@ -145,3 +148,3 @@ // Other types do an instanceof check.

// Error if it returned string.
throw new instanceError(format(result, value, name));
throw new err(format(result, value, name));
}

@@ -155,4 +158,4 @@

* @param {string} name Name of the value (prefixed to error messages to assist debugging).
* @param {Error} instanceError Type of error that gets thrown if values don't match types.
* @param {Object} instanceCheckers An object listing checkers for a Blork isntance.
* @param {Error} err Type of error that gets thrown if values don't match types.
* @param {Object} checkers An object listing checkers for a Blork isntance.
* @param {Array} typeStack The stack of parent types to track infinite loops.

@@ -166,10 +169,10 @@ * @param {Array} valueStack The stack of parent values to track infinite loops.

*/
function checkArray(value, type, name, instanceError, instanceCheckers, typeStack, valueStack) {
function checkArray(value, type, name, err, checkers, typeStack, valueStack) {
// Value must be an array (reuse the checker logic too.
checkInternal(value, "array", name, instanceError, instanceCheckers, typeStack, valueStack);
checkInternal(value, "array", name, err, checkers, typeStack, valueStack);
// Prevent infinite loops.
if (typeStack.indexOf(type) !== -1)
if (valueStack.indexOf(value) >= 0) return 1;
if (typeStack.indexOf(type) >= 0)
throw new BlorkError(format("Blork type must not contain circular references", value, name));
if (valueStack.indexOf(value) !== -1) return 1;
typeStack.push(type);

@@ -187,14 +190,3 @@ valueStack.push(value);

for (let i = 0; i < l; i++)
if (
checkInternal(
value[i],
type[0],
`${prefix}[${i}]`,
instanceError,
instanceCheckers,
typeStack,
valueStack
)
)
pass++;
if (checkInternal(value[i], type[0], `${prefix}[${i}]`, err, checkers, typeStack, valueStack)) pass++;
} else {

@@ -204,18 +196,6 @@ // Tuple array: Loop through types and match each with a value recursively.

for (let i = 0; i < l; i++)
if (
checkInternal(
value[i],
type[i],
`${prefix}[${i}]`,
instanceError,
instanceCheckers,
typeStack,
valueStack
)
)
pass++;
if (checkInternal(value[i], type[i], `${prefix}[${i}]`, err, checkers, typeStack, valueStack)) pass++;
// No excess items in a tuple.
if (value.length > l)
throw new instanceError(format(`Too many array items (expected ${l})`, value.length, prefix));
if (value.length > l) throw new err(format(`Too many array items (expected ${l})`, value.length, prefix));
}

@@ -235,4 +215,4 @@

* @param {string} name Name of the value (prefixed to error messages to assist debugging).
* @param {Error} instanceError Type of error that gets thrown if values don't match types.
* @param {Object} instanceCheckers An object listing checkers for a Blork isntance.
* @param {Error} err Type of error that gets thrown if values don't match types.
* @param {Object} checkers An object listing checkers for a Blork isntance.
* @param {Array} typeStack The stack of parent types to track infinite loops.

@@ -246,29 +226,47 @@ * @param {Array} valueStack The stack of parent values to track infinite loops.

*/
function checkObject(value, type, name, instanceError, instanceCheckers, typeStack, valueStack) {
function checkObject(value, type, name, err, checkers, typeStack, valueStack) {
// Value must be an object (reuse the checker logic too.
checkInternal(value, "object", name, instanceError, instanceCheckers, typeStack, valueStack);
checkInternal(value, "object", name, err, checkers, typeStack, valueStack);
// Prevent infinite loops.
if (typeStack.indexOf(type) !== -1)
if (valueStack.indexOf(value) >= 0) return 1;
if (typeStack.indexOf(type) >= 0)
throw new BlorkError(format("Blork type must not contain circular references", value, name));
if (valueStack.indexOf(value) !== -1) return 1;
typeStack.push(type);
valueStack.push(value);
// Recurse into each type.
// Vars.
let pass = 0;
for (const key in type)
if (
checkInternal(
value[key],
type[key],
name ? `${name}[${key}]` : key,
instanceError,
instanceCheckers,
typeStack,
valueStack
)
)
pass++;
const typeKeys = Object.keys(type);
// Loop through each item in the types object.
// No need to ignore the ANY key as Object.keys() doesn't get Symbol keys.
for (let i = 0; i < typeKeys.length; i++) {
const key = typeKeys[i];
const prefix = name ? `${name}[${key}]` : key;
if (checkInternal(value[key], type[key], prefix, err, checkers, typeStack, valueStack)) pass++;
}
// Is there an ANY key?
if (type.hasOwnProperty(ANY)) {
// Vars.
const valueKeys = Object.keys(value);
// Check that we actually need to do this loop by comparing the lengths.
if (valueKeys.length > typeKeys.length) {
// Make a list of the excess keys (that are in valueKeys but not in typeKeys).
const excessKeys = valueKeys.filter(v => typeKeys.indexOf(v) === -1);
// Loop through all excess keys.
for (let i = 0; i < excessKeys.length; i++) {
// Vars.
const key = excessKeys[i];
const prefix = name ? `${name}[${key}]` : key;
// Check all excess keys against the ANY type.
if (checkInternal(value[key], type[ANY], prefix, err, checkers, typeStack, valueStack)) pass++;
}
}
}
// Pass.

@@ -275,0 +273,0 @@ typeStack.pop();

const blork = require("./blork");
const debug = require("./debug");
const format = require("./format");
const { ANY } = require("./constants");

@@ -9,8 +10,9 @@ // Make a default instance.

// Exports.
module.exports.blork = blork;
module.exports.args = args;
module.exports.check = check;
module.exports.throws = throws;
module.exports.add = add;
module.exports.format = format;
module.exports.debug = debug;
exports.blork = blork;
exports.args = args;
exports.check = check;
exports.throws = throws;
exports.add = add;
exports.format = format;
exports.debug = debug;
exports.ANY = ANY;
{
"name": "blork",
"description": "Blork! Mini runtime type checking in Javascript",
"version": "3.4.1",
"version": "3.5.0",
"license": "0BSD",

@@ -6,0 +6,0 @@ "author": "Dave Houlbrooke <dave@shax.com>",

@@ -7,3 +7,3 @@ # Blork! Mini runtime type checking in Javascript

A mini type checker for locking down the external edges of your code. Mainly for use in modules when you don't know who'll be using the code. Minimal boilerplate code keeps your functions hyper readable and lets them be their beautiful minimal best selves (...or something?)
A mini type checker for locking down the external edges of your code. Mainly for use in modules when you don"t know who'll be using the code. Minimal boilerplate code keeps your functions hyper readable and lets them be their beautiful minimal best selves (...or something?)

@@ -28,3 +28,3 @@ Blork is fully unit tested and 100% covered (if you're into that!).

```js
import { args } from 'blork';
import { args } from "blork";

@@ -35,17 +35,17 @@ // An exported function other (untrusted) developers may use.

// Check the args.
args(arguments, ['string', 'number?']);
args(arguments, ["string", "number?"]);
// Rest of the function.
return 'It passed!';
return "It passed!";
}
// Call with good args.
myFunc('abc', 123); // Returns "It passed!"
myFunc('abc'); // Returns "It passed!"
myFunc("abc", 123); // Returns "It passed!"
myFunc("abc"); // Returns "It passed!"
// Call with invalid args.
myFunc(123); // Throws TypeError "arguments[0]: Must be string (received 123)"
myFunc('abc', 'abc'); // Throws TypeError "arguments[1]: Must be number (received 'abc')"
myFunc("abc", "abc"); // Throws TypeError "arguments[1]: Must be number (received "abc")"
myFunc(); // Throws TypeError "arguments[0]: Must be string (received undefined)"
myFunc('abc', 123, true); // Throws TypeError "arguments: Too many arguments (expected 2) (received 3)"
myFunc("abc", 123, true); // Throws TypeError "arguments: Too many arguments (expected 2) (received 3)"
```

@@ -64,15 +64,15 @@

```js
import { check } from 'blork';
import { check } from "blork";
// Checks that pass.
check('Sally', 'string'); // Returns 1
check('Sally', String); // Returns 1
check("Sally", "string"); // Returns 1
check("Sally", String); // Returns 1
// Checks that fail.
check('Sally', 'number'); // Throws TypeError "Must be a number (received 'Sally')"
check('Sally', Boolean); // Throws TypeError "Must be true or false (received 'Sally')"
check("Sally", "number"); // Throws TypeError "Must be a number (received "Sally")"
check("Sally", Boolean); // Throws TypeError "Must be true or false (received "Sally")"
// Checks that fail (with a name set).
check('Sally', 'num', 'name'); // Throws TypeError "name: Must be a number (received 'Sally')"
check(true, 'str', 'status'); // Throws TypeError "status: Must be a string (received true)"
check("Sally", "num", "name"); // Throws TypeError "name: Must be a number (received "Sally")"
check(true, "str", "status"); // Throws TypeError "status: Must be a string (received true)"
```

@@ -85,13 +85,13 @@

```js
// This check fails because it's not optional.
check(undefined, 'number'); // Throws TypeError "Must be a number (received undefined)"
// This check fails because it"s not optional.
check(undefined, "number"); // Throws TypeError "Must be a number (received undefined)"
// This check passes because it's optional.
check(undefined, 'number?'); // Returns 0
// This check passes because it"s optional.
check(undefined, "number?"); // Returns 0
// Null does not count as optional.
check(null, 'number?'); // Throws TypeError "Must be a number (received null)"
check(null, "number?"); // Throws TypeError "Must be a number (received null)"
```
_`check()` and `args()` return the number of **defined** values that passed. i.e. If a check passes because it's optional it will return `0` as shown above._
_`check()` and `args()` return the number of **defined** values that passed. i.e. If a check passes because it"s optional it will return `0` as shown above._

@@ -104,15 +104,15 @@ ### Checking objects and arrays

// Check object properties.
check({ name: 'Sally' }, { name: 'string' }); // Returns 1
check({ name: "Sally" }, { name: "string" }); // Returns 1
// Check all array items.
check(['Sally', 'John', 'Sonia'], ['str']); // Returns 3
check(["Sally", "John", "Sonia"], ["str"]); // Returns 3
// Check tuple-style array.
check([1029, 'Sonia'], ['number', 'string']); // Returns 2
check([1029, "Sonia"], ["number", "string"]); // Returns 2
// Failing checks.
check({ name: 'Sally' }, { name: 'string' }); // Returns 1
check(['Sally', 'John', 'Sonia'], ['str']); // Returns 3
check([1029, 'Sonia'], ['number', 'string']); // Returns 2
check([1029, 'Sonia', true], ['number', 'string']); // Throws TypeError: "Array: Too many array items (expected 2) (received 3)"
check({ name: "Sally" }, { name: "string" }); // Returns 1
check(["Sally", "John", "Sonia"], ["str"]); // Returns 3
check([1029, "Sonia"], ["number", "string"]); // Returns 2
check([1029, "Sonia", true], ["number", "string"]); // Throws TypeError: "Array: Too many array items (expected 2) (received 3)"
```

@@ -127,4 +127,4 @@

[
{ id: 1028, name: 'Sally', status: [1, 2, 3] },
{ id: 1062, name: 'Bobby', status: [1, 2, 3] }
{ id: 1028, name: "Sally", status: [1, 2, 3] },
{ id: 1062, name: "Bobby", status: [1, 2, 3] }
],

@@ -137,7 +137,7 @@ [

// Deeply nested check (fails).
// Will throw TypeError "Array[1][status][2]: Must be a number (received 'not_a_number')"
// Will throw TypeError "Array[1][status][2]: Must be a number (received "not_a_number")"
check(
[
{ id: 1028, name: 'Sally', status: [1, 2, 3] },
{ id: 1062, name: 'Bobby', status: [1, 2, 'not_a_number'] }
{ id: 1028, name: "Sally", status: [1, 2, 3] },
{ id: 1062, name: "Bobby", status: [1, 2, "not_a_number"] }
],

@@ -155,19 +155,19 @@ [

```js
import { add, check } from 'blork';
import { add, check } from "blork";
// Register your new checker.
add('catty', (v) => {
// Check it's a string containing 'cat', or return an error message.
return typeof v === 'string' && v.indexOf('cat') >= 0 || "Must be a string containing 'cat'";
add("catty", (v) => {
// Check it"s a string containing "cat", or return an error message.
return typeof v === "string" && v.indexOf("cat") >= 0 || "Must be a string containing 'cat'";
});
// Passes.
check('That cat is having fun', 'catty'); // Returns 1.
check("That cat is having fun", "catty"); // Returns 1.
// Fails.
check('A dog sits on the chair', 'catty'); // Throws TypeError "Must be a string containing 'cat' (received 'A dog sits on the chair')"
check("A dog sits on the chair", "catty"); // Throws TypeError "Must be a string containing "cat" (received "A dog sits on the chair")"
```
```js
import { add, args } from 'blork';
import { add, args } from "blork";

@@ -177,11 +177,11 @@ // Use your checker to check function args.

{
args(arguments, ['catty']);
return 'It passed!';
args(arguments, ["catty"]);
return "It passed!";
}
// Passes.
myFunc('That cat is chasing string'); // Returns "It passed!"
myFunc("That cat is chasing string"); // Returns "It passed!"
// Fails.
myFunc('A dog sits over there'); // Throws TypeError "arguments[1]: Must be a string containing 'cat' (received 'A dog sits over there')"
myFunc("A dog sits over there"); // Throws TypeError "arguments[1]: Must be a string containing "cat" (received "A dog sits over there")"
```

@@ -194,3 +194,3 @@

```js
import { throws, check } from 'blork';
import { throws, check } from "blork";

@@ -204,3 +204,3 @@ // Make a custom error type for yourself.

// Test a value.
check(true, 'false'); // Throws MyError "Must be false (received true)"
check(true, "false"); // Throws MyError "Must be false (received true)"
```

@@ -215,3 +215,3 @@

```js
import { blork } from 'blork';
import { blork } from "blork";

@@ -233,2 +233,4 @@ // Create a new set of functions from Blork.

### String types
Types are generally accessed via a string reference. This list shows all Blork built-in checkers:

@@ -282,14 +284,16 @@

// Pass.
check('abc', 'str'); // Returns 1
check('abc', 'lower'); // Returns 1
check(100, 'whole'); // Returns 1
check([1, 2, 3], 'array+'); // Returns 1
check(new Date(2180, 1, 1), 'future'); // Returns 1
check("abc", "str"); // Returns 1
check("abc", "lower"); // Returns 1
check(100, "whole"); // Returns 1
check([1, 2, 3], "array+"); // Returns 1
check(new Date(2180, 1, 1), "future"); // Returns 1
// Fail.
check(123, 'str'); // Throws TypeError "Must be string (received 123)"
check({}, 'object+'); // Throws TypeError "Must be object with one or more properties (received Object(0))"
check([], 'array+'); // Throws TypeError "Must be array with one or more items (received Array(0))"
check(123, "str"); // Throws TypeError "Must be string (received 123)"
check({}, "object+"); // Throws TypeError "Must be object with one or more properties (received Object(0))"
check([], "array+"); // Throws TypeError "Must be array with one or more items (received Array(0))"
```
### Optional string types
Any type can be made optional by appending a `?` question mark to the type reference. This means the check will also accept `undefined` in addition to the specified type.

@@ -301,28 +305,34 @@

// Pass.
check(undefined, 'str?'); // Returns 0 (not 1)
check(undefined, 'lower?'); // Returns 0 (not 1)
check(undefined, 'whole?'); // Returns 0 (not 1)
check([undefined, undefined, 123], ['number?']); // Returns 1 (not 3)
check(undefined, "str?"); // Returns 0 (not 1)
check(undefined, "lower?"); // Returns 0 (not 1)
check(undefined, "whole?"); // Returns 0 (not 1)
check([undefined, undefined, 123], ["number?"]); // Returns 1 (not 3)
// Fail.
check(123, 'str?'); // Throws TypeError "Must be string (received 123)"
check(null, 'str?'); // Throws TypeError "Must be string (received null)"
check(123, "str?"); // Throws TypeError "Must be string (received 123)"
check(null, "str?"); // Throws TypeError "Must be string (received null)"
```
For convenience constructors can also be used as types in `args()` and `check()`. The following built-in objects can be used:
### Constructor and constant types
| Type | Description |
|-----------|----------------------------|
| `Boolean` | Same as **'boolean'** type |
| `String` | Same as **'string'** type |
| `Number` | Same as **'number'** type |
| `Array` | Same as **'array'** type |
| `Object` | Same as **'object'** type |
For convenience some constructors (e.g. `String`) and constants (e.g. `null`) can be used as types in `args()` and `check()`. The following built-in objects and constants are supported:
You can also pass in _any_ class name, and Blork will check the value using `instanceof` and generate a corresponding error message if the type doesn't match.
| Type | Description |
|-------------|------------------------------|
| `Boolean` | Same as **'boolean'** type |
| `String` | Same as **'string'** type |
| `Number` | Same as **'number'** type |
| `true` | Same as **'true'** type |
| `false` | Same as **'false'** type |
| `null` | Same as **'null'** type |
| `undefined` | Same as **'undefined'** type |
You can pass in _any_ class name, and Blork will check the value using `instanceof` and generate a corresponding error message if the type doesn't match.
Using `Object` and `Array` constructors will work also and will allow any object that is `instanceof Object` or `instanceof Array`. _Note: this is not the same as e.g. the `'object'` and `'array'` string types, which only allow plain objects an arrays (but will reject objects of custom classes extending `Object` or `Array`)._
```js
// Pass.
check(true, Boolean); // Returns 1
check('abc', String); // Returns 1
check("abc", String); // Returns 1
check(123, Number); // Returns 1

@@ -336,46 +346,82 @@ check(new Date, Date); // Returns 1

// Fail.
check('abc', Boolean); // Throws TypeError "Must be true or false (received 'abc')"
check('abc', String); // Throws TypeError "Must be a string (received 'abc')"
check('abc', String, 'myVar'); // Throws TypeError "myVar: Must be a string (received 'abc')"
check("abc", Boolean); // Throws TypeError "Must be true or false (received "abc")"
check("abc", String); // Throws TypeError "Must be a string (received "abc")"
check("abc", String, "myVar"); // Throws TypeError "myVar: Must be a string (received "abc")"
check(new MyClass, OtherClass); // Throws TypeError "Must be an instance of OtherClass (received MyClass)"
check({ name: 123 }, { name: String }); // Throws TypeError "name: Must be a string (received 123)"
check({ name: 123 }, { name: String }, 'myObj'); // Throws TypeError "myObj[name]: Must be a string (received 123)"
check({ name: 123 }, { name: String }, "myObj"); // Throws TypeError "myObj[name]: Must be a string (received 123)"
```
To check the types of object properties, pass an object as the type. You can also deeply nest these properties and the types will be checked recursively and will generate useful debuggable error messages.
### Object literal type
To check the types of object properties, use a literal object as a type. You can also deeply nest these properties and the types will be checked recursively and will generate useful debuggable error messages.
_Note: it is fine for objects to contain additional properties that don't have a type specified._
```js
// Pass.
check({ name: 'abc' }, { name: 'str' }); // Returns 1
check({ name: 'abc' }, { name: 'str?', age: 'num?' }); // Returns 1 (age is optional)
check({ name: "abc" }, { name: "str" }); // Returns 1
check({ name: "abc" }, { name: "str?", age: "num?" }); // Returns 1 (age is optional)
check({ name: "abc", additional: true }, { name: "str" }); // Returns 1 (additional properties are fine)
// Fail.
check({ age: '28' }, { age: 'num' }); // Throws TypeError "age: Must be a number (received '28')"
check({ age: "apple" }, { age: "num" }); // Throws TypeError "age: Must be a number (received "apple")"
check({ size: { height: 10, width: "abc" } }, { size: { height: "num", width: "num" } }); // Throws TypeError "size[width]: Must be a number (received "abc")"
```
To check an array where all items conform to a specific type, pass an array as the type. Other objects and arrays can be nested to check types recursively.
### Object literal type (with additional properties)
To check that the type of **all** properties in an object all conform to a type, use an `ANY` key. This allows you to check objects that don't have known keys (e.g. from user generated data). This is similar to how indexer keys work in Flow or Typescript.
```js
import { check, ANY } from "blork";
// Pass.
check(['abc', 'abc'], ['str']); // Returns 2
check([123, 123], ['num']); // Returns 2
check({ a: 1, b: 2, c: 3 }, { [ANY]: "num" }); // Returns 3
check({ name: "Dan", a: 1, b: 2, c: 3 }, { name: "str", [ANY]: "num" }); // Returns 4
// Fail.
check(['abc', 'abc', 123], ['str']); // Throws TypeError "Array[2]: Must be a number (received 123)"
check(['abc', 'abc', 123], ['number']); // Throws TypeError "Array[0]: Must be a string (received 'abc')"
check({ a: 1, b: 2, c: "abc" }, { [ANY]: "num" }); // Throws TypeError "c: Must be a number (received "abc")"
```
Similarly, to check the format of tuples, pass an array with two or more items as the type. _If two or more items are in the array, it is considered a tuple type._
If you wish you can use this functionality with the `undefined` type to ensure objects **do not** contain additional properties (object literal types by default are allowed to contain additional properties).
```js
// Pass.
check([123, 'abc'], ['num', 'str']); // Returns 2
check([123, 'abc'], ['num', 'str', 'str?']); // Returns 2 (third item is optional)
check({ name: "Carl" }, { name: "str", [ANY]: "undefined" }); // Returns 1;
// Fail.
check([123], ['num', 'str']); // Throws TypeError "Array[1]: Must be a string (received undefined)"
check([123, 123], ['num', 'str']); // Throws TypeError "Array[1]: Must be a string (received 123)"
check([123, 'abc', true], ['num', 'str']); // Throws TypeError "Array: Too many items (expected 2 but received 3)"
check({ name: "Jess", another: 28 }, { name: "str", [ANY]: "undefined" }); // Throws TypeError "another: Must be undefined (received 28)"
```
### Array literal type
To check an array where all items conform to a specific type, pass an array as the type. Arrays and objects can be deeply nested to check types recursively.
```js
// Pass.
check(["abc", "abc"], ["str"]); // Returns 2
check([123, 123], ["num"]); // Returns 2
check([{ names: ["Alice", "John"] }], [{ names: ["str"] }]); // Returns 1
// Fail.
check(["abc", "abc", 123], ["str"]); // Throws TypeError "Array[2]: Must be a number (received 123)"
check(["abc", "abc", 123], ["number"]); // Throws TypeError "Array[0]: Must be a string (received "abc")"
```
### Array tuple type
Similarly, to check the format of tuples, pass an array with two or more items as the type. _If two or more types are in an type array, it is considered a tuple type and will be rejected if it does not conform exactly to the tuple._
```js
// Pass.
check([123, "abc"], ["num", "str"]); // Returns 2
check([123, "abc"], ["num", "str", "str?"]); // Returns 2 (third item is optional)
// Fail.
check([123], ["num", "str"]); // Throws TypeError "Array[1]: Must be a string (received undefined)"
check([123, 123], ["num", "str"]); // Throws TypeError "Array[1]: Must be a string (received 123)"
check([123, "abc", true], ["num", "str"]); // Throws TypeError "Array: Too many items (expected 2 but received 3)"
```
## Contributing

@@ -382,0 +428,0 @@

@@ -5,127 +5,12 @@ const BlorkError = require("../lib/BlorkError");

// Tests.
describe("check() value", () => {
test("Pass correctly when object value contains circular references", () => {
const value = {};
value.circular = value;
expect(check(value, { circular: { circular: Object } })).toBe(1);
});
test("Pass correctly when array value contains circular references", () => {
const value = [];
value.push(value);
expect(check(value, [[Array]])).toBe(1);
});
test("Throw TypeError when object value is not plain object", () => {
expect(check(new class {}(), Object)).toBe(1);
});
test("Object literal types pass correctly", () => {
expect(check({ a: "a", b: 1 }, { a: "str", b: Number })).toBe(2);
expect(check({ a: "a", z: "extraparam" }, { a: String })).toBe(1); // Objects ignore extra params.
expect(check({ a: "a", b: undefined }, { a: "str", b: "num?" })).toBe(1); // Objects don't count undefined optional values.
});
test("Object literal types fail correctly", () => {
expect(() => check({ a: "notnumberparam" }, { a: Number })).toThrow(TypeError);
});
test("Throw TypeError if value is not object (object literal format)", () => {
expect(() => check(123, { "1": Number })).toThrow(TypeError);
});
test("Array literal types pass correctly", () => {
expect(check([1, 2, 3], [Number])).toBe(3);
expect(check([1, 2, 3], ["num"])).toBe(3);
expect(check([1, undefined, 3], ["num?"])).toBe(2); // Arrays don't count undefined optional values.
});
test("Array literal types fail correctly", () => {
expect(() => check([1, 2, "surprisestring"], [Number])).toThrow(TypeError);
});
test("Throw TypeError if value is not array (array literal format)", () => {
expect(() => check({ a: 123 }, [String])).toThrow(TypeError);
});
test("Return correctly when checks pass (array tuple format)", () => {
expect(check([1, 2, 3], [Number, Number, Number])).toBe(3);
expect(check([1, 2, 3], ["num", "num", "num"])).toBe(3);
expect(check([1, undefined, 3], ["num?", "num?", "num?"])).toBe(2); // Arrays don't count undefined optional values.
});
test("Throw TypeError when checks fail (array tuple format)", () => {
expect(() => check([1, 1], [Number, String])).toThrow(TypeError);
expect(() => check([1, "b", "excessitem"], [Number, String])).toThrow(TypeError);
});
test("Throw TypeError if value is not array (array tuple format)", () => {
expect(() => check({ a: 123 }, [String])).toThrow(TypeError);
});
});
describe("check() type", () => {
test("Throw BlorkError if string type does not exist", () => {
expect(() => check(1, "checkerthatdoesnotexist")).toThrow(BlorkError);
});
test("Throw BlorkError when array type contains circular references", () => {
const type = [];
type.push(type);
expect(() => check([[]], type)).toThrow(BlorkError);
});
test("Throw BlorkError when object type contain circular references", () => {
const type = {};
type.circular = type;
expect(() => check({ circular: { circular: {} } }, type)).toThrow(BlorkError);
});
test("Optional types pass correctly", () => {
expect(check(1, "number?")).toBe(1);
expect(check("a", "string?")).toBe(1);
expect(check({}, "object?")).toBe(1);
expect(check(undefined, "number?")).toBe(0);
expect(check(undefined, "string?")).toBe(0);
expect(check(undefined, "object?")).toBe(0);
});
test("Optional types fail correctly", () => {
expect(() => check("a", "number?")).toThrow(TypeError);
expect(() => check(1, "string?")).toThrow(TypeError);
expect(() => check(1, "object?")).toThrow(TypeError);
});
test("Throw BlorkError if type is not object, function, or string", () => {
describe("check()", () => {
test("Throw BlorkError if type is not object, function, string, or one of our known types", () => {
expect(() => check(1, 123)).toThrow(BlorkError);
expect(() => check(1, true)).toThrow(BlorkError);
expect(() => check(1, null)).toThrow(BlorkError);
expect(() => check(1, undefined)).toThrow(BlorkError);
});
test("Constructor types pass correctly", () => {
expect(check(true, Boolean)).toBe(1);
expect(check(1, Number)).toBe(1);
expect(check("a", String)).toBe(1);
expect(check({}, Object)).toBe(1);
expect(check([], Array)).toBe(1);
expect(check(Promise.resolve(true), Promise)).toBe(1);
test("Literal types true, false, null, and undefined all work correctly", () => {
expect(check(true, true)).toBe(1);
expect(check(false, false)).toBe(1);
expect(check(null, null)).toBe(1);
expect(check(undefined, undefined)).toBe(1);
});
test("Constructor types fail correctly", () => {
expect(() => check(1, Boolean)).toThrow(TypeError);
expect(() => check("a", Number)).toThrow(TypeError);
expect(() => check(null, String)).toThrow(TypeError);
expect(() => check("a", Object)).toThrow(TypeError);
expect(() => check({}, Array)).toThrow(TypeError);
expect(() => check({}, Promise)).toThrow(TypeError);
expect(() => check(1, Boolean)).toThrow(/Must be true or false/);
expect(() => check("a", Number)).toThrow(/Must be a finite number/);
expect(() => check(null, String)).toThrow(/Must be a string/);
expect(() => check("a", Object)).toThrow(/Must be an instance of Object/);
expect(() => check({}, Array)).toThrow(/Must be an instance of Array/);
expect(() => check({}, Promise)).toThrow(/Must be an instance of Promise/);
});
test("Custom constructor types pass correctly", () => {
class MyClass {}
const myClass = new MyClass();
expect(check(myClass, MyClass)).toBe(1);
class MySubClass extends MyClass {}
const mySubClass = new MySubClass();
expect(check(mySubClass, MyClass)).toBe(1);
});
test("Custom constructor checks fail correctly", () => {
class MyClass {}
class MyOtherClass {}
const myClass = new MyClass();
expect(() => check(myClass, MyOtherClass)).toThrow(TypeError);
expect(() => check(myClass, MyOtherClass)).toThrow(/Must be an instance of MyOtherClass/);
expect(() => check(myClass, class {})).toThrow(TypeError);
expect(() => check(myClass, class {})).toThrow(/Must be an instance of anonymous class/);
expect(() => check(myClass, function() {})).toThrow(TypeError);
expect(() => check(myClass, function() {})).toThrow(/Must be an instance of anonymous class/);
});
});
describe("check() name", () => {
test("Do not throw error if passing string name", () => {

@@ -132,0 +17,0 @@ expect(check(true, "bool", "myValue")).toBe(1);

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