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 7.0.2 to 7.1.0

lib/modifiers.js

123

lib/classes/Blorker.js

@@ -1,14 +0,7 @@

// @flow
const ValueError = require("../errors/ValueError");
const BlorkError = require("../errors/BlorkError");
const format = require("../functions/format");
const modifiers = require("../modifiers");
const { CLASS, KEYS, VALUES } = require("../constants");
// Vars.
const R_AND = /\s*&+\s*/;
const R_OR = /\s*\|+\s*/;
const R_INVERT = /^!/;
const R_NONEMPTY = /\+$/;
const R_OPTIONAL = /\?+$/;
/**

@@ -66,2 +59,5 @@ * Check a value with a specified checker.

this._checkers = Object.assign({}, checkers);
// Bind find (we use this a few times).
this._find = this._find.bind(this);
}

@@ -79,3 +75,3 @@

// Return the checker.
const checker = this._checkers[type];
const checker = this._checkers[type] || this._lazyCreateChecker(type) || false;
if (checker) return checker;

@@ -259,103 +255,14 @@

_lazyCreateChecker(type) {
// AND checkers (two string checkers joined with "&")
if (~type.indexOf("&")) {
// Split type and get corresponding checker for each.
const ands = type.split(R_AND).map(this._find, this);
// Loop through modifiers.
for (const i in modifiers) {
// Test the type against the modifier's regex.
const matches = type.match(modifiers[i].regex);
// Check each checker.
const andChecker = value => {
// Loop through and call each checker.
for (const checker of ands) if (!checker(value)) return false; // Fail.
return true; // Otherwise pass.
};
// Description message joins the descriptions for the checkers.
andChecker.desc = ands.map(checker => checker.desc).join(" and ");
// Add the AND checker to the list of checkers now it has been created.
this._checkers[type] = andChecker;
return andChecker;
// Did the regex match?
if (matches) {
// Yes! Call the modifier's callback to (lazily) create the type.
this._checkers[type] = modifiers[i].callback(matches, this._find);
return this._checkers[type]; // And return it.
}
}
// OR checkers (two string checkers joined with "|")
if (~type.indexOf("|")) {
// Split type and get corresponding checker for each.
const ors = type.split(R_OR).map(this._find, this);
// Check each checker.
const orChecker = value => {
// Loop through and call each checker.
for (const checker of ors) if (checker(value)) return true; // Pass.
return false; // Otherwise fail.
};
// Description message joins the descriptions for the checkers.
orChecker.desc = ors.map(checker => checker.desc).join(" or ");
// Add the OR checker to the list of checkers now it has been created.
this._checkers[type] = orChecker;
return orChecker;
}
// Inverted value (starts with '!'), e.g. "!num"
if (R_INVERT.test(type)) {
// Find non optional checker (strip '!').
const checker = this._find(type.replace(R_INVERT, ""));
// Create an optional checker for this optional type.
// Returns 0 if undefined, or passes through to the normal checker.
const invertedChecker = v => !checker(v);
// Description message joins the descriptions for the checkers.
invertedChecker.desc = `not ${checker.desc}`;
// Add the invertedChecker to the list and return it.
this._checkers[type] = invertedChecker;
return invertedChecker;
}
// Non-empty value (ends with '+'), e.g. "str+"
if (R_NONEMPTY.test(type)) {
// Find non optional checker (strip '+').
const checker = this._find(type.replace(R_NONEMPTY, ""));
// Create a length checker for this optional type.
// Returns true if checker passes and there's a numeric length or size property with a value of >0.
const lengthChecker = v => {
// Must pass the checker.
if (!checker(v)) return false;
// Map and Set use .size
if (v instanceof Map || v instanceof Set) return v.size > 0;
// String and Array use .length
if (typeof v === "string" || v instanceof Array) return v.length > 0;
// Objects use key length.
if (typeof v === "object" && v !== null) return Object.keys(v).length > 0;
// Everything else (numbers, booleans, null, undefined) do a falsy check.
return !!v;
};
// Description message joins the descriptions for the checkers.
lengthChecker.desc = `non-empty ${checker.desc}`;
// Add the lengthChecker to the list and return it.
this._checkers[type] = lengthChecker;
return lengthChecker;
}
// Optional value (ends with '?'), e.g. "num?"
if (R_OPTIONAL.test(type)) {
// Find non optional checker (strip '?').
const checker = this._find(type.replace(R_OPTIONAL, ""));
// Create an optional checker for this optional type.
// Returns 0 if undefined, or passes through to the normal checker.
const optionalChecker = v => (v === undefined ? true : checker(v));
// Description message joins the descriptions for the checkers.
optionalChecker.desc = `${checker.desc} or empty`;
// Add the optionalChecker to the list and return it.
this._checkers[type] = optionalChecker;
return optionalChecker;
}
}

@@ -362,0 +269,0 @@

{
"name": "blork",
"description": "Blork! Mini runtime type checking in Javascript",
"version": "7.0.2",
"version": "7.1.0",
"license": "0BSD",

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

@@ -457,2 +457,44 @@ # Blork! Mini runtime type checking in Javascript

### String modifiers: Array types
Any string type can be made into an array of that type by appending `[]` brackets to the type reference. This means the check looks for a plain array whose contents only include the specified type.
```js
// Pass.
check(["a", "b"], "str[]"); // No error.
check([1, 2, 3], "int[]"); // No error.
check([], "int[]"); // No error (empty is fine).
check([1], "int[]+"); // No error (non-empty).
// Fail.
check([1, 2], "str[]"); // Throws ValueError "Must be plain array containing only string (received [1, 2])"
check(["a"], "int[]"); // Throws ValueError "Must be plain array containing only integer (received ["a"])"
check([], "int[]+"); // Throws ValueError "Must be non-empty plain array containing only integer (received [])"
```
### String modifiers: Object types
Check for objects only containing strings of a specified type by surrounding the type in `{}` braces. This means the check looks for a plain object whose contents only include the specified type (whitespace is optional).
```js
// Pass.
check({ a: "a", b: "b" }, "{str}"); // No error.
check({ a: 1, b: 2 }, "{int}"); // No error.
check({}, "{int}"); // No error (empty is fine).
check({ a: 1 }, "{int}+"); // No error (non-empty).
// Fail.
check({ a: 1, b: 2 }, "{str}"); // Throws ValueError "Must be plain object containing only string (received [1, 2])"
check({ a: "a" }, "{int}"); // Throws ValueError "Must be plain object containing only integer (received ["a"])"
check({}, "{int}+"); // Throws ValueError "Must be non-empty plain object containing only integer (received [])"
```
A type for the keys can also be specified by using `key: value` format.
```js
// Pass.
check({ myVar: 123 }, "{ camel: integer }");
check({ "my-var": 123 }, "{ kebab: integer }");
```
### String modifiers: Optional types

@@ -730,2 +772,4 @@

- 7.1.0
- Add object and array string modifiers (using `type[]`, `{type}` and `{ keyType: type }` syntax)
- 7.0.0

@@ -732,0 +776,0 @@ - Add `VALUES`, `KEYS`, and `CLASS` symbol constants

@@ -5,2 +5,3 @@ const BlorkError = require("../lib/errors/BlorkError");

// Tests.
/* eslint-disable prettier/prettier */
describe("exports.check() string types", () => {

@@ -86,2 +87,41 @@ test("String types pass correctly", () => {

});
describe("Array types", () => {
test("Array types pass correctly", () => {
expect(check([1, 2, 3], "num[]")).toBe(undefined);
expect(check(["a", "b"], "lower[]")).toBe(undefined);
expect(check([true, false], "bool[]")).toBe(undefined);
});
test("Array types fail correctly", () => {
expect(() => check(true, "num[]")).toThrow(TypeError);
expect(() => check(false, "num[]")).toThrow(TypeError);
expect(() => check([1, 2, "c"], "num[]")).toThrow(TypeError);
expect(() => check(["a", "b", 3], "str[]")).toThrow(TypeError);
expect(() => check([], "str[]+")).toThrow(TypeError);
expect(() => check(["a", "b", ""], "str+[]")).toThrow(TypeError);
});
test("Array types have correct error message", () => {
expect(() => check(true, "str[]")).toThrow(/plain array containing only string/);
expect(() => check([], "str[]+")).toThrow(/non-empty plain array containing only string/);
expect(() => check(["a", "b", ""], "str+[]")).toThrow(/plain array containing only non-empty string/);
});
});
describe("Object types", () => {
test("Object types pass correctly", () => {
expect(check({ "a": 1, "b": 2, "c": 3 }, "{num}")).toBe(undefined);
expect(check({ "a": "A", "b": "A" }, "{ upper }")).toBe(undefined);
expect(check({ "aaAA": true, "bbBB": false }, "{ camel: bool }")).toBe(undefined);
expect(check({ "aa-aa": true, "bb-bb": false }, "{ slug: bool }")).toBe(undefined);
});
test("Object types fail correctly", () => {
expect(() => check(true, "{num}")).toThrow(TypeError);
expect(() => check(false, "{num}")).toThrow(TypeError);
expect(() => check([1, 2, 3], "{ num }")).toThrow(TypeError);
expect(() => check({ aaAA: true, bbBB: false }, "{ kebab: bool }")).toThrow(TypeError);
expect(() => check({ "aa-aa": true, "bb-bb": false }, "{ camel: bool }")).toThrow(TypeError);
});
test("Object types have correct error message", () => {
expect(() => check(true, "{int}")).toThrow(/plain object containing only integer/);
expect(() => check({ "ABC": true }, "{ upper: int }")).toThrow(/plain object with UPPERCASE-only string keys containing only integer/);
});
});
describe("Combined types", () => {

@@ -119,16 +159,6 @@ test("AND combined types pass correctly", () => {

test("AND and OR combined types have correct error message", () => {
expect(() => check("ABCdef", "string & lower | upper")).toThrow(/string/);
expect(() => check("ABCdef", "string & lower | upper")).toThrow(/and/);
expect(() => check("ABCdef", "string & lower | upper")).toThrow(/or/);
expect(() => check("ABCdef", "string & lower | upper")).toThrow(/UPPERCASE/);
expect(() => check("ABCdef", "string & lower | upper")).toThrow(/lowercase/);
expect(() => check("ABCdef", "string & lower | upper")).toThrow(/string/);
expect(() => check("ABCdef", "lower | upper & string")).toThrow(/string/);
expect(() => check("ABCdef", "lower | upper & string")).toThrow(/and/);
expect(() => check("ABCdef", "lower | upper & string")).toThrow(/or/);
expect(() => check("ABCdef", "lower | upper & string")).toThrow(/UPPERCASE/);
expect(() => check("ABCdef", "lower | upper & string")).toThrow(/lowercase/);
expect(() => check("ABCdef", "lower | upper & string")).toThrow(/string/);
expect(() => check(1, "string & string | string")).toThrow(/string and string or string/);
expect(() => check(1, "string | string & string")).toThrow(/string or string and string/);
});
});
});
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