core-functions
Advanced tools
Comparing version 3.0.20 to 3.0.21
17
any.js
@@ -14,3 +14,6 @@ 'use strict'; | ||
exports.valueOf = valueOf; | ||
exports.toType = toType; | ||
const objectToString = Object.prototype.toString; | ||
/** | ||
@@ -44,1 +47,15 @@ * Determines whether the given value is defined (i.e. NOT undefined and NOT null) or not. | ||
/** | ||
* Returns the type of the given value that would be reported by either `.constructor.name` or `Object.prototype.toString`. | ||
* Note that primitive numbers will return 'Number', primitive strings will return 'String' & primitive booleans will | ||
* return 'Boolean'. | ||
* @param {*} value - the value for which to resolve its type | ||
* @return {string} a string representing the value's type, e.g. 'Object', 'Error', 'Number', 'String', ... | ||
*/ | ||
function toType(value) { | ||
if (value && typeof value === 'object' && value.constructor && value.constructor.name) { | ||
return value.constructor.name; | ||
} | ||
const t = objectToString.call(value); | ||
return t.substring(t.indexOf(' ') + 1, t.length - 1); | ||
} |
"use strict"; | ||
const isInstanceOf = require('./objects').isInstanceOf; | ||
const strings = require('./strings'); | ||
@@ -134,2 +136,9 @@ const isNotBlank = strings.isNotBlank; | ||
/** A MethodNotAllowed error (HTTP status 405) */ | ||
class MethodNotAllowed extends AppError { | ||
constructor(message, code, cause) { | ||
super(message, code, 405, cause); | ||
} | ||
} | ||
/** A RequestTimeout error (HTTP status 408) */ | ||
@@ -195,6 +204,7 @@ class RequestTimeout extends AppError { | ||
// Special case - error is already an AppError and no message and code were provided or they are the same values | ||
if (error instanceof AppError && (!message || error.message === message) && (!code || error.code === code)) { | ||
const instanceOfAppError = isInstanceOf(error, AppError); | ||
if (instanceOfAppError && (!message || error.message === message) && (!code || error.code === code)) { | ||
return error; | ||
} | ||
const httpStatus = error instanceof AppError ? error.httpStatus : getHttpStatus(error); | ||
const httpStatus = instanceOfAppError ? error.httpStatus : getHttpStatus(error); | ||
if (isNotBlank(httpStatus)) { | ||
@@ -210,2 +220,4 @@ switch (httpStatus) { | ||
return new NotFound(message, code, error); | ||
case 405: | ||
return new MethodNotAllowed(message, code, error); | ||
case 408: | ||
@@ -396,3 +408,3 @@ return new RequestTimeout(message, code, error); | ||
const causeMessage = | ||
cause instanceof AppError && cause.cause ? | ||
isInstanceOf(cause, AppError) && cause.cause ? | ||
cause.cause : // if AppError, use underlying cause if any | ||
@@ -417,2 +429,3 @@ cause instanceof Error ? | ||
exports.NotFound = NotFound; | ||
exports.MethodNotAllowed = MethodNotAllowed; | ||
exports.RequestTimeout = RequestTimeout; | ||
@@ -419,0 +432,0 @@ exports.TooManyRequests = TooManyRequests; |
@@ -8,2 +8,3 @@ 'use strict'; | ||
const any = require('./any'); | ||
const toType = any.toType; | ||
@@ -30,2 +31,3 @@ const propertyIsEnumerable = Object.prototype.propertyIsEnumerable; | ||
exports.getOwnPropertyNamesRecursively = getOwnPropertyNamesRecursively; | ||
exports.isInstanceOf = isInstanceOf; | ||
@@ -347,1 +349,32 @@ /** @deprecated use {@linkcode core-functions/any#valueOf} instead */ | ||
} | ||
/** | ||
* Returns true if the given object is "probably" an instance of the given type, without relying solely on the broken | ||
* `instanceof` operator. When `instanceof` returns false or if a string type name is passed, then this method falls | ||
* back on using `any.toType` to match the object's type against the given type. | ||
* @param {Object} object - the object instance to check | ||
* @param {Function|string} type - the constructor function or name of the type against which to compare | ||
* @return {boolean} true if "probably" an instance | ||
*/ | ||
function isInstanceOf(object, type) { | ||
if (!object || typeof object !== 'object' || !type) { | ||
return false; | ||
} | ||
function isInstanceOfType(object, type) { | ||
if (object instanceof type || toType(object) === type.name) return true; | ||
const prototype = Object.getPrototypeOf(object); | ||
return !prototype || prototype === Object.prototype ? type.name === 'Object' : | ||
isInstanceOfType(prototype, type); | ||
} | ||
function isInstanceOfTypeName(object, typeName) { | ||
if (toType(object) === typeName) return true; | ||
const prototype = Object.getPrototypeOf(object); | ||
return !prototype || prototype === Object.prototype ? typeName === 'Object' : | ||
isInstanceOfTypeName(prototype, typeName); | ||
} | ||
return typeof type === 'function' ? isInstanceOfType(object, type) : | ||
typeof type === 'string' ? isInstanceOfTypeName(object, type) : false; | ||
} |
{ | ||
"name": "core-functions", | ||
"version": "3.0.20", | ||
"version": "3.0.21", | ||
"description": "Core functions, utilities and classes for working with Node/JavaScript primitives and built-in objects, including strings, booleans, Promises, base 64, Arrays, Objects, standard AppErrors, etc.", | ||
@@ -5,0 +5,0 @@ "author": "Byron du Preez", |
'use strict'; | ||
const isInstanceOf = require('./objects').isInstanceOf; | ||
const tries = require('./tries'); | ||
@@ -557,5 +559,5 @@ const Try = tries.Try; | ||
return isPromiseLike(value) ? value.then(join) : | ||
value instanceof Success ? value.map(join) : | ||
isInstanceOf(value, Success) ? value.map(join) : | ||
Array.isArray(value) ? | ||
value.some(v => isPromiseLike(v) || v instanceof Success) ? | ||
value.some(v => isPromiseLike(v) || isInstanceOf(v, Success)) ? | ||
every(value.map(join), cancellable, logger).then(os => simplifyOutcomes ? Try.simplify(os) : os) : | ||
@@ -568,5 +570,5 @@ value : | ||
isThenable(value) ? toPromise(value).then(join) : | ||
value instanceof Try ? value.toPromise().then(join) : | ||
isInstanceOf(value, Try) ? value.toPromise().then(join) : | ||
Array.isArray(value) ? | ||
value.some(v => isPromiseLike(v) || v instanceof Success) ? | ||
value.some(v => isPromiseLike(v) || isInstanceOf(v, Success)) ? | ||
every(value.map(join), cancellable, logger).then(os => simplifyOutcomes ? Try.simplify(os) : os) : | ||
@@ -573,0 +575,0 @@ Promise.resolve(value) : |
@@ -1,2 +0,2 @@ | ||
# core-functions v3.0.20 | ||
# core-functions v3.0.21 | ||
@@ -3,0 +3,0 @@ Core functions, utilities and classes for working with Node/JavaScript primitives and built-in objects, including |
## Changes | ||
### 3.0.21 | ||
- Added `toType` function to `any` module | ||
- Added `isInstanceOf` function to `objects` module | ||
- Replaced all of the `instanceof` checks against custom classes with calls to `isInstanceOf` | ||
- Added `MethodNotAllowed` class to `app-errors` module | ||
### 3.0.20 | ||
@@ -4,0 +10,0 @@ - Updated usage notes and tested with Node version number in `README.md` |
@@ -14,2 +14,3 @@ 'use strict'; | ||
const valueOf = any.valueOf; | ||
const toType = any.toType; | ||
@@ -192,2 +193,34 @@ const strings = require('../strings'); | ||
t.end(); | ||
}); | ||
test('toType', t => { | ||
function check(value, expected) { | ||
t.equals(toType(value), expected, `toType(${JSON.stringify(value)}) must be ${expected}`); | ||
} | ||
check(undefined, 'Undefined'); | ||
check(null, 'Null'); | ||
check({}, 'Object'); | ||
check({a:1}, 'Object'); | ||
check(new Error('Boom'), 'Error'); | ||
check(new ReferenceError('Type ... Boom'), 'ReferenceError'); | ||
check(new TypeError('Type ... Boom'), 'TypeError'); | ||
check([], 'Array'); | ||
check([1,2,3], 'Array'); | ||
check(true, 'Boolean'); | ||
check(false, 'Boolean'); | ||
check('', 'String'); | ||
check('abc', 'String'); | ||
check(0, 'Number'); | ||
check(123, 'Number'); | ||
check(-123, 'Number'); | ||
check(NaN, 'Number'); | ||
t.end(); | ||
}); |
@@ -15,2 +15,3 @@ 'use strict'; | ||
const hasOwnPropertyWithCompoundName = Objects.hasOwnPropertyWithCompoundName; | ||
const isInstanceOf = Objects.isInstanceOf; | ||
@@ -174,1 +175,74 @@ const strings = require('../strings'); | ||
}); | ||
test(`isInstanceOf`, t => { | ||
function check(object, type, expected) { | ||
const typeName = type.name ? type.name : `"${type}"`; | ||
t.equals(isInstanceOf(object, type), expected, `isInstanceOf(${JSON.stringify(object)}, ${typeName}) must be ${expected}`); | ||
} | ||
check(null, Object, false); | ||
check(undefined, Object, false); | ||
check(1, Object, false); | ||
check('abc', Object, false); | ||
check(true, Object, false); | ||
check(false, Object, false); | ||
check({}, Object, true); | ||
check({}, 'Object', true); | ||
check({a:1}, Object, true); | ||
check({a:1}, 'Object', true); | ||
check([], Object, true); | ||
check([], Array, true); | ||
check([], Number, false); | ||
check([], 'Object', true); | ||
check([], 'Array', true); | ||
check([], 'Number', false); | ||
const error = new Error(); | ||
check(error, Object, true); | ||
check(error, Error, true); | ||
check(error, TypeError, false); | ||
check(error, ReferenceError, false); | ||
check(error, String, false); | ||
check(error, 'Object', true); | ||
check(error, 'Error', true); | ||
check(error, 'TypeError', false); | ||
check(error, 'ReferenceError', false); | ||
check(error, 'String', false); | ||
const typeError = new TypeError(); | ||
check(typeError, Object, true); | ||
check(typeError, Error, true); | ||
check(typeError, TypeError, true); | ||
check(typeError, ReferenceError, false); | ||
check(typeError, String, false); | ||
check(typeError, 'Object', true); | ||
check(typeError, 'Error', true); | ||
check(typeError, 'TypeError', true); | ||
check(typeError, 'ReferenceError', false); | ||
check(typeError, 'String', false); | ||
const referenceError = new ReferenceError(); | ||
check(referenceError, Object, true); | ||
check(referenceError, Error, true); | ||
check(referenceError, ReferenceError, true); | ||
check(referenceError, TypeError, false); | ||
check(referenceError, String, false); | ||
check(referenceError, 'Object', true); | ||
check(referenceError, 'Error', true); | ||
check(referenceError, 'ReferenceError', true); | ||
check(referenceError, 'TypeError', false); | ||
check(referenceError, 'String', false); | ||
t.end(); | ||
}); |
34
tries.js
'use strict'; | ||
const isInstanceOf = require('./objects').isInstanceOf; | ||
exports._$_ = '_$_'; //IDE workaround | ||
@@ -33,3 +35,3 @@ | ||
// Automatically flatten if any given argument is already a Try | ||
if (arguments.length > 0 && (arguments[0] instanceof Try)) return arguments[0]; | ||
if (arguments.length > 0 && isInstanceOf(arguments[0], Try)) return arguments[0]; | ||
} | ||
@@ -47,3 +49,3 @@ | ||
const value = typeof f === 'function' ? f() : f; | ||
return value instanceof Try ? value : new Success(value); | ||
return isInstanceOf(value, Try) ? value : new Success(value); | ||
} catch (err) { | ||
@@ -155,3 +157,3 @@ return new Failure(err); | ||
static simplify(outcomes) { | ||
return outcomes.every(o => o instanceof Success) ? outcomes.map(o => o.value) : outcomes; | ||
return outcomes.every(o => isInstanceOf(o, Success)) ? outcomes.map(o => o.value) : outcomes; | ||
} | ||
@@ -177,3 +179,3 @@ | ||
static countSuccess(outcomes, strict) { | ||
const isSuccess = strict ? o => o instanceof Success : o => !(o instanceof Failure); | ||
const isSuccess = strict ? o => isInstanceOf(o, Success) : o => !isInstanceOf(o, Failure); | ||
return outcomes.reduce((acc, o) => acc + (isSuccess(o) ? 1 : 0), 0); | ||
@@ -188,3 +190,3 @@ } | ||
static countFailure(outcomes) { | ||
return outcomes.reduce((acc, o) => acc + (o instanceof Failure ? 1 : 0), 0); | ||
return outcomes.reduce((acc, o) => acc + (isInstanceOf(o, Failure) ? 1 : 0), 0); | ||
} | ||
@@ -235,3 +237,3 @@ | ||
const isTryType = value instanceof TryType; | ||
const isTryType = isInstanceOf(value, TryType); | ||
const isArray = Array.isArray(value); | ||
@@ -254,6 +256,6 @@ const v = isTryType ? value.get() : isArray ? new Array(value.length) : value; | ||
// Recurse deeper if maximum depth has not been reached yet & if its still worthwhile to do so | ||
const mustTraverse = depth > 0 && value.some(e => e instanceof TryType || Array.isArray(e)); | ||
const mustTraverse = depth > 0 && value.some(e => isInstanceOf(e, TryType) || Array.isArray(e)); | ||
for (let i = 0; i < value.length; ++i) { | ||
const e = value[i]; | ||
const ev = e instanceof TryType ? e.get() : e; | ||
const ev = isInstanceOf(e, TryType) ? e.get() : e; | ||
v[i] = mustTraverse ? unpack(ev, depth - 1) : ev; | ||
@@ -289,6 +291,6 @@ } | ||
if (value instanceof Failure) | ||
if (isInstanceOf(value, Failure)) | ||
return value; | ||
if (value instanceof Success) { | ||
if (isInstanceOf(value, Success)) { | ||
// Search deeper if maximum depth has not been reached yet | ||
@@ -301,4 +303,4 @@ return depth > 0 ? find(value.value, depth - 1) : undefined; | ||
// return undefined) | ||
const f = value.find(e => e instanceof Failure); | ||
// const f = depth > 0 ? value.find(e => e instanceof Failure) : undefined; | ||
const f = value.find(e => isInstanceOf(e, Failure)); | ||
// const f = depth > 0 ? value.find(e => isInstanceOf(e, Failure)) : undefined; | ||
if (f) | ||
@@ -308,5 +310,5 @@ return f; | ||
// Search deeper if maximum depth has not been reached yet & if its still worthwhile to do so | ||
if (depth > 0 && value.some(e => (e instanceof Success) || Array.isArray(e))) { | ||
if (depth > 0 && value.some(e => isInstanceOf(e, Success) || Array.isArray(e))) { | ||
for (let e of value) { | ||
const f = find(e instanceof Success ? e.value : e, depth - 1); | ||
const f = find(isInstanceOf(e, Success) ? e.value : e, depth - 1); | ||
if (f) | ||
@@ -340,3 +342,3 @@ return f; | ||
// Automatically flatten if value is already a Try | ||
if (value instanceof Try) return value; | ||
if (isInstanceOf(value, Try)) return value; | ||
super(); | ||
@@ -396,3 +398,3 @@ // Set an enumerable, non-configurable, read-only value property to the given value | ||
// Automatically flatten if error is already a Try | ||
if (error instanceof Try) return error; | ||
if (isInstanceOf(error, Try)) return error; | ||
super(); | ||
@@ -399,0 +401,0 @@ // Set an enumerable, non-configurable, read-only error property to the given error |
'use strict'; | ||
const isInstanceOf = require('./objects').isInstanceOf; | ||
/** | ||
@@ -33,3 +35,3 @@ * Module containing a WeakMap subclass to be used for creating "copies" of existing WeakMaps. | ||
if (WeakMap.prototype.has.call(this, key)) { | ||
return !(WeakMap.prototype.get.call(this, key) instanceof Deleted); | ||
return !isInstanceOf(WeakMap.prototype.get.call(this, key), Deleted); | ||
} | ||
@@ -45,3 +47,3 @@ // Cache original value in this copy for consistency of later possible re-get of same value | ||
const value = WeakMap.prototype.get.call(this, key); | ||
return !(value instanceof Deleted) ? value : undefined; | ||
return !isInstanceOf(value, Deleted) ? value : undefined; | ||
} | ||
@@ -58,3 +60,3 @@ // Cache original value in this copy for consistency of later possible re-get of same value | ||
const value = WeakMap.prototype.get.call(this, key); | ||
if (!(value instanceof Deleted)) { | ||
if (!isInstanceOf(value, Deleted)) { | ||
WeakMap.prototype.delete.call(this, key); | ||
@@ -61,0 +63,0 @@ // Simulate deletion by caching DELETED, which will avoid a later `get` pulling a value from original |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
979393
15664
45