Comparing version 1.1.3 to 1.1.4
@@ -12,3 +12,3 @@ "use strict"; | ||
'falsy': (v) => !v || 'Must be falsy', | ||
'number': (v) => typeof v === 'number' || 'Must be number', | ||
'number': (v) => typeof v === 'number' || 'Must be a number', | ||
'integer': (v) => (typeof v === 'number' && Number.isInteger(v) && v >= Number.MIN_SAFE_INTEGER && v <= Number.MAX_SAFE_INTEGER) || 'Must be an integer', | ||
@@ -24,3 +24,3 @@ 'natural': (v) => (typeof v === 'number' && Number.isInteger(v) && v > 0 && v <= Number.MAX_SAFE_INTEGER) || 'Must be a natural number, e.g. 1, 2, 3', | ||
'uppercase+': (v) => (typeof v === 'string' && v.length > 0 && v === v.toUpperCase()) || 'Must be a non-empty uppercase string', | ||
'function': (v) => v instanceof Function || 'Must be an function', | ||
'function': (v) => v instanceof Function || 'Must be a function', | ||
'object': (v) => (typeof v === 'object' && v !== null) || 'Must be an object', | ||
@@ -32,3 +32,3 @@ 'object+': (v) => (typeof v === 'object' && v !== null && Object.keys(v).length > 0) || 'Must be an object with one or more enumerable properties', | ||
'map': (v) => v instanceof Map || 'Must be a map', | ||
'map+': (v) => (v instanceof Map && v.size > 0) || 'Must be a non-empty map', | ||
'map+': (v) => (v instanceof Map && v.size > 0) || 'Must be a map', | ||
'weakmap': (v) => v instanceof WeakMap || 'Must be a weak map', | ||
@@ -35,0 +35,0 @@ 'set': (v) => v instanceof Set || 'Must be a set', |
@@ -7,41 +7,44 @@ "use strict"; | ||
return 'null'; | ||
if (value === undefined) | ||
else if (value === undefined) | ||
return 'undefined'; | ||
if (value === true) | ||
else if (value === true) | ||
return 'true'; | ||
if (value === false) | ||
else if (value === false) | ||
return 'false'; | ||
if (typeof value === 'string') { | ||
const max = 20; | ||
return JSON.stringify(value.length > max ? `${value.substr(0, max)}…` : value); | ||
} | ||
if (typeof value === 'number') | ||
else if (typeof value === 'number') | ||
return value.toString(); | ||
if (typeof value === 'symbol') | ||
else if (typeof value === 'symbol') | ||
return value.toString(); | ||
else if (typeof value === 'string') | ||
return JSON.stringify(value); | ||
else | ||
return debugObject(value); | ||
} | ||
exports.debug = debug; | ||
function debugObject(value) { | ||
if (value instanceof Function) { | ||
if (value.name.length > 0) | ||
return `function ${value.name}()`; | ||
return `${value.name}()`; | ||
return 'anonymous function'; | ||
} | ||
if (value instanceof Array) | ||
return value.length > 0 ? `${value.constructor.name} with ${value.length} items` : `empty ${value.constructor.name}`; | ||
if (value instanceof Object) { | ||
if (value.constructor instanceof Function && value.constructor.name.length > 0) { | ||
if (value.constructor === Object) { | ||
const l = Object.keys(value).length; | ||
return l > 0 ? `Object with ${l} props` : 'empty Object'; | ||
} | ||
return `instance of ${value.constructor.name}`; | ||
} | ||
return 'instance of anonymous class'; | ||
if (value.constructor instanceof Function && value.constructor.name.length > 0) { | ||
if (value instanceof Error) | ||
return `${value.constructor.name} ${debug(value.message)}`; | ||
if (value instanceof Date) | ||
return value.toISOString(); | ||
if (value.constructor === RegExp) | ||
return value.toString(); | ||
if (value.constructor === Array) | ||
return JSON.stringify(value, undefined, '\t'); | ||
if (value.constructor === Object) | ||
return JSON.stringify(value, undefined, '\t'); | ||
return `instance of ${value.constructor.name}`; | ||
} | ||
return 'unknown value'; | ||
return 'instance of anonymous class'; | ||
} | ||
exports.debug = debug; | ||
function format(message, value = UNDEF, prefix) { | ||
const debugged = debug(value); | ||
return (typeof prefix === 'string' && prefix.length > 0 ? `${prefix}: ` : '') + message + (value !== UNDEF ? ` (received ${debugged})` : ''); | ||
return (typeof prefix === 'string' && prefix.length > 0 ? `;$;{prefix;}: ` : '') + message + (value !== UNDEF ? ` (received ${debugged})` : ''); | ||
} | ||
exports.format = format; | ||
//# sourceMappingURL=helpers.js.map |
@@ -47,7 +47,4 @@ "use strict"; | ||
break; | ||
case Object: | ||
result = checkers_1.checkers.obj(value); | ||
break; | ||
default: if (!(value instanceof type)) | ||
result = `Must be instance of ${(type.name || 'specified object')}`; | ||
result = `Must be an instance of ${type.name || 'anonymous class'}`; | ||
} | ||
@@ -54,0 +51,0 @@ if (result === true) |
{ | ||
"name": "blork", | ||
"description": "Blork! Mini runtime type checking in Javascript", | ||
"version": "1.1.3", | ||
"version": "1.1.4", | ||
"license": "0BSD", | ||
@@ -26,3 +26,3 @@ "author": "Dave Houlbrooke <dave@shax.com>", | ||
"pretest": "npm run build", | ||
"test": "jest", | ||
"test": "jest --coverage", | ||
"watch": "jest --watchAll", | ||
@@ -34,3 +34,16 @@ "precommit": "npm run build && npm run test" | ||
"url": "git://github.com/dhoulb/blork.git" | ||
}, | ||
"jest": { | ||
"coverageReporters": [ | ||
"text" | ||
], | ||
"coverageThreshold": { | ||
"global": { | ||
"branches": 100, | ||
"functions": 100, | ||
"lines": 100, | ||
"statements": 100 | ||
} | ||
} | ||
} | ||
} |
@@ -20,3 +20,3 @@ /** | ||
'falsy': (v: any) => !v || 'Must be falsy', | ||
'number': (v: any) => typeof v === 'number' || 'Must be number', | ||
'number': (v: any) => typeof v === 'number' || 'Must be a number', | ||
'integer': (v: any) => (typeof v === 'number' && Number.isInteger(v) && v >= Number.MIN_SAFE_INTEGER && v <= Number.MAX_SAFE_INTEGER) || 'Must be an integer', | ||
@@ -32,3 +32,3 @@ 'natural': (v: any) => (typeof v === 'number' && Number.isInteger(v) && v > 0 && v <= Number.MAX_SAFE_INTEGER) || 'Must be a natural number, e.g. 1, 2, 3', | ||
'uppercase+': (v: any) => (typeof v === 'string' && v.length > 0 && v === v.toUpperCase()) || 'Must be a non-empty uppercase string', | ||
'function': (v: any) => v instanceof Function || 'Must be an function', | ||
'function': (v: any) => v instanceof Function || 'Must be a function', | ||
'object': (v: any) => (typeof v === 'object' && v !== null) || 'Must be an object', | ||
@@ -40,3 +40,3 @@ 'object+': (v: any) => (typeof v === 'object' && v !== null && Object.keys(v).length > 0) || 'Must be an object with one or more enumerable properties', | ||
'map': (v: any) => v instanceof Map || 'Must be a map', | ||
'map+': (v: any) => (v instanceof Map && v.size > 0) || 'Must be a non-empty map', | ||
'map+': (v: any) => (v instanceof Map && v.size > 0) || 'Must be a map', | ||
'weakmap': (v: any) => v instanceof WeakMap || 'Must be a weak map', | ||
@@ -43,0 +43,0 @@ 'set': (v: any) => v instanceof Set || 'Must be a set', |
@@ -11,5 +11,5 @@ /** | ||
* Neatly convert any value into a string for debugging. | ||
* | ||
* @param value The value to convert to a string. | ||
* @return The value after it has been converted to a string. | ||
* @param value The value to debug. | ||
* @return String representing the debugged value. | ||
* @internal | ||
*/ | ||
@@ -19,32 +19,57 @@ export function debug(value: any) { // tslint:disable-line:no-any | ||
if (value === null) return 'null'; | ||
if (value === undefined) return 'undefined'; | ||
if (value === true) return 'true'; | ||
if (value === false) return 'false'; | ||
if (typeof value === 'string') { | ||
const max = 20; | ||
return JSON.stringify(value.length > max ? `${value.substr(0, max)}…` : value); | ||
} | ||
if (typeof value === 'number') return value.toString(); // E.g. 123 or 456.789 | ||
if (typeof value === 'symbol') return value.toString(); // E.g. Symbol(foo) | ||
else if (value === undefined) return 'undefined'; | ||
else if (value === true) return 'true'; | ||
else if (value === false) return 'false'; | ||
else if (typeof value === 'number') return value.toString(); // E.g. 123 or 456.789 | ||
else if (typeof value === 'symbol') return value.toString(); // E.g. Symbol(foo) | ||
else if (typeof value === 'string') return JSON.stringify(value); | ||
else return debugObject(value as object); | ||
} | ||
/** | ||
* Debug an object. | ||
* @param value The value to debug. | ||
* @return String representing the debugged value. | ||
* @internal | ||
*/ | ||
function debugObject(value: object): string { | ||
// Function, e.g. myFunc() | ||
if (value instanceof Function) { | ||
// tslint:disable:no-unsafe-any | ||
if (value.name.length > 0) return `function ${value.name}()`; | ||
// tslint:enable:no-unsafe-any | ||
// Named function. | ||
if (value.name.length > 0) return `${value.name}()`; // tslint:disable-line:no-unsafe-any | ||
// Unnamed function. | ||
return 'anonymous function'; | ||
} | ||
if (value instanceof Array) return value.length > 0 ? `${value.constructor.name} with ${value.length} items` : `empty ${value.constructor.name}`; | ||
if (value instanceof Object) { | ||
// tslint:disable:no-unsafe-any | ||
if (value.constructor instanceof Function && value.constructor.name.length > 0) { | ||
if (value.constructor === Object) { | ||
const l = Object.keys(value).length; | ||
return l > 0 ? `Object with ${l} props` : 'empty Object'; | ||
} | ||
return `instance of ${value.constructor.name}`; | ||
} | ||
// tslint:enable:no-unsafe-any | ||
return 'instance of anonymous class'; | ||
// tslint:disable:no-unsafe-any | ||
if (value.constructor instanceof Function && value.constructor.name.length > 0) { | ||
// Error, e.g. TypeError "Must be a string" | ||
if (value instanceof Error) return `${value.constructor.name} ${debug(value.message)}`; | ||
// Date, e.g. 2011-10-05T14:48:00.000Z | ||
if (value instanceof Date) return value.toISOString(); | ||
// Regular expression, e.g. /abc/ | ||
if (value.constructor === RegExp) return value.toString(); | ||
// Array, e.g. Array: [1,3,4] | ||
if (value.constructor === Array) return JSON.stringify(value, undefined, '\t'); | ||
// Object, e.g. Object: {"a":123} | ||
if (value.constructor === Object) return JSON.stringify(value, undefined, '\t'); | ||
// Other object with named constructor. | ||
return `instance of ${value.constructor.name}`; | ||
} | ||
return 'unknown value'; | ||
// tslint:enable:no-unsafe-any | ||
// Other unnamed object. | ||
return 'instance of anonymous class'; | ||
} | ||
@@ -67,4 +92,4 @@ | ||
// E.g. MyPrefix: Must be string (received 123) | ||
return (typeof prefix === 'string' && prefix.length > 0 ? `${prefix}: ` : '') + message + (value !== UNDEF ? ` (received ${debugged})` : ''); | ||
return (typeof prefix === 'string' && prefix.length > 0 ? `;$;{prefix;}: ` : '') + message + (value !== UNDEF ? ` (received ${debugged})` : ''); | ||
} |
@@ -110,6 +110,5 @@ /** | ||
case String: result = checkers.str(value); break; | ||
case Object: result = checkers.obj(value); break; | ||
// Other types do an instanceof check. | ||
default: if (!(value instanceof type)) result = `Must be instance of ${(type.name || 'specified object')}`; | ||
default: if (!(value instanceof type)) result = `Must be an instance of ${type.name || 'anonymous class'}`; | ||
@@ -116,0 +115,0 @@ } |
const { BlorkError } = require('../lib/errors'); | ||
const { checkers } = require('../lib/checkers'); | ||
const { debug } = require('../lib/helpers'); | ||
const { check, args, add, throws } = require('../lib/blork'); | ||
// Vars. | ||
const func = () => {}; | ||
// Tests. | ||
@@ -157,2 +153,8 @@ describe('check()', () => { | ||
expect(() => check({}, Promise)).toThrow(TypeError); | ||
expect(() => check(1, Boolean)).toThrow(/Must be true or false/); | ||
expect(() => check('a', Number)).toThrow(/Must be a 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/); | ||
}); | ||
@@ -168,3 +170,11 @@ test('Return correctly when checks pass (custom constructor format)', () => { | ||
test('Throw TypeError when checks fail (custom constructor format)', () => { | ||
expect(() => check(1, Boolean)).toThrow(TypeError); | ||
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/); | ||
}); | ||
@@ -174,2 +184,3 @@ test('Return correctly when checks pass (object literal format)', () => { | ||
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. | ||
}); | ||
@@ -179,4 +190,9 @@ test('Throw TypeError when checks fail (object literal format)', () => { | ||
}); | ||
test('Throw TypeError if value is not object (object literal format)', () => { | ||
expect(() => check(123, { '1': Number })).toThrow(TypeError); | ||
}); | ||
test('Return correctly when checks pass (array literal format)', () => { | ||
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. | ||
}); | ||
@@ -186,4 +202,9 @@ test('Throw TypeError when checks fail (array literal format)', () => { | ||
}); | ||
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. | ||
}); | ||
@@ -194,2 +215,5 @@ test('Throw TypeError when checks fail (array tuple format)', () => { | ||
}); | ||
test('Throw TypeError if value is not array (array tuple format)', () => { | ||
expect(() => check({ a: 123 }, [String])).toThrow(TypeError); | ||
}); | ||
test('Throw BlorkError if type is not object, function, or string', () => { | ||
@@ -201,5 +225,14 @@ expect(() => check(1, 123)).toThrow(BlorkError); | ||
}); | ||
test('Do not throw error if passing string name', () => { | ||
expect(check(true, 'bool', 'myValue')).toBe(1); | ||
expect(check(true, Boolean, 'myValue')).toBe(1); | ||
expect(check([true], ['bool'], 'myValue')).toBe(1); | ||
expect(check({ bool: true }, { bool: 'bool' }, 'myValue')).toBe(1); | ||
}); | ||
test('Throw BlorkError if passing non-string name', () => { | ||
expect(() => check(1, 'bool', 123)).toThrow(BlorkError); | ||
}); | ||
test('Throw BlorkError if checker does not exist', () => { | ||
expect(() => check(1, 'checkerthatdoesnotexist')).toThrow(BlorkError); | ||
}); | ||
}); | ||
@@ -210,3 +243,11 @@ describe('args()', () => { | ||
expect(args(argsObj, [String, Number, Boolean])).toBe(3); | ||
const argsArr = ['a', 123, true]; | ||
expect(args(argsArr, [String, Number, Boolean])).toBe(3); | ||
}); | ||
test('Return correct number when arguments are optional', () => { | ||
const argsObj = { '0': 'a', '1': 123, length: 2 }; | ||
expect(args(argsObj, ['str', 'num', 'bool?'])).toBe(2); | ||
const argsArr = ['a', 123]; | ||
expect(args(argsArr, ['str', 'num', 'bool?'])).toBe(2); | ||
}); | ||
test('Throw TypeError when argument checks fail', () => { | ||
@@ -236,2 +277,3 @@ const argsObj = { '0': 'a', length: 3 }; | ||
test('Throw BlorkError if not non-empty lowercase string', () => { | ||
const func = () => {}; | ||
expect(() => add(123, func)).toThrow(BlorkError); | ||
@@ -245,2 +287,3 @@ expect(() => add('', func)).toThrow(BlorkError); | ||
test('Throw BlorkError if same name as existing', () => { | ||
const func = () => {}; | ||
add('test.checker.samename', func); | ||
@@ -247,0 +290,0 @@ expect(() => add('test.checker.samename', func)).toThrow(BlorkError); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
82818
1082