core-functions
Advanced tools
Comparing version 3.0.2 to 3.0.4
@@ -9,3 +9,4 @@ /** | ||
isDistinct: isDistinct, | ||
isArrayOfType: isArrayOfType | ||
isArrayOfType: isArrayOfType, | ||
flatten: flatten | ||
}; | ||
@@ -70,1 +71,17 @@ | ||
} | ||
/** | ||
* Flattens the given Array of Array and/or non-Array elements into a single new Array containing all of the given | ||
* Array's unpacked Array elements' elements together with all of its own non-Array elements. | ||
* @param {*[][]} array - an Array of Array and/or non-Array elements | ||
* @returns {*[]} a single Array containing all of the elements of the given arrays | ||
*/ | ||
function flatten(array) { | ||
return array.reduce((acc, e) => { | ||
if (Array.isArray(e)) | ||
acc.push.apply(acc, e); | ||
else | ||
acc.push(e); | ||
return acc; | ||
}, []); | ||
} |
{ | ||
"name": "core-functions", | ||
"version": "3.0.2", | ||
"version": "3.0.4", | ||
"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.", | ||
@@ -8,3 +8,3 @@ "author": "Byron du Preez", | ||
"engines": { | ||
"node": ">=4.3.2" | ||
"node": ">=6.10" | ||
}, | ||
@@ -11,0 +11,0 @@ "scripts": { |
@@ -89,5 +89,5 @@ 'use strict'; | ||
/** Installs the given cancelTimeout function onto the given cancellable object */ | ||
installCancelTimeout: installCancelTimeout | ||
// /** Replaces the cancel method on the given cancellable object with a new cancel method that will invoke both its original cancel method and the new, next cancellable's cancel method. */ | ||
// extendCancel: extendCancel | ||
installCancelTimeout: installCancelTimeout, | ||
/** Attaches an arbitrary `catch` clause to the given promise to avoid an unneeded UnhandledPromiseRejectionWarning */ | ||
avoidUnhandledPromiseRejectionWarning: avoidUnhandledPromiseRejectionWarning | ||
}; | ||
@@ -384,3 +384,3 @@ | ||
installCancel(cancellable, () => { | ||
cancelled = true; | ||
if (!completed) cancelled = true; | ||
return completed; | ||
@@ -474,22 +474,19 @@ }); | ||
// If value is a promise or promise-like then flatten its resolved value or rejected error | ||
return value.then( | ||
v => flatten(v, cancellable, opts), | ||
err => { | ||
throw err; | ||
} | ||
); | ||
const p = value.then(v => flatten(v, cancellable, opts)); | ||
avoidUnhandledPromiseRejectionWarning(p); | ||
return p; | ||
} | ||
const isArray = Array.isArray(value); | ||
if (isArray && value.some(v => isPromiseLike(v))) { | ||
// If value is an array containing at least one Promise or promise-like, then first flatten all of its promises and | ||
// then use `every` function to flatten all of its resulting promises into a single promise of outcomes | ||
// If value is an array containing at least one Promise or promise-like, then first flatten each of its promises and | ||
// then use the `every` function to "flatten" all of its resulting promises into a single promise of "simplified" outcomes | ||
const promise = every(value.map(v => flatten(v, cancellable, opts)), cancellable); | ||
return !opts || !opts.skipSimplifyOutcomes ? promise.then(outcomes => Try.simplify(outcomes)) : promise; | ||
} else if (value instanceof Try) { | ||
} else if (value instanceof Success) { | ||
// If value is a Success outcome, then flatten its Success value too | ||
return value.map(v => flatten(v, cancellable, opts)); | ||
} else if (isArray && value.some(v => v instanceof Try)) { | ||
// If value is an array containing at least one Success or Failure outcome, then flatten any Success values too | ||
} else if (isArray && value.some(v => v instanceof Success)) { | ||
// If value is an array containing at least one Success outcome, then flatten any Success values too | ||
const outcomes = value.map(v => v instanceof Success ? v.map(vv => flatten(vv, cancellable, opts)) : v); | ||
@@ -545,3 +542,3 @@ return !opts || !opts.skipSimplifyOutcomes ? Try.simplify(outcomes) : outcomes; | ||
installCancel(cancellable, () => { | ||
cancelled = true; | ||
if (!completed) cancelled = true; | ||
return completed; | ||
@@ -629,25 +626,13 @@ }); | ||
// /** | ||
// * Replaces the `cancel` method on the given cancellable object with a new `cancel` method that will invoke both its | ||
// * original `cancel` method (if any) and the given next cancellable's `cancel` method (if any). | ||
// * @param {Cancellable} cancellable - the original cancellable, whose `cancel` method will be replaced/extended | ||
// * @param {Cancellable} nextCancellable - the next cancellable, whose `cancel` method will be invoked by the | ||
// * cancellable's new `cancel` method | ||
// */ | ||
// function extendCancel(cancellable, nextCancellable) { | ||
// if (cancellable && typeof cancellable === 'object' && nextCancellable && typeof nextCancellable === 'object') { | ||
// const originalCancel = cancellable.cancel; | ||
// cancellable.cancel = () => { | ||
// let completed = true; | ||
// if (nextCancellable.cancel) { | ||
// const nextCompleted = nextCancellable.cancel(); | ||
// completed = completed && nextCompleted; | ||
// } | ||
// if (originalCancel) { | ||
// const originalCompleted = originalCancel.call(cancellable); | ||
// completed = completed && originalCompleted; | ||
// } | ||
// return completed; | ||
// }; | ||
// } | ||
// } | ||
/** | ||
* Attaches an arbitrary `catch` clause to the given promise to avoid an unneeded UnhandledPromiseRejectionWarning. | ||
* @param {Promise|PromiseLike|*} p - a promise to which to attach an arbitrary `catch` | ||
*/ | ||
function avoidUnhandledPromiseRejectionWarning(p) { | ||
if (p && p.catch) { | ||
p.catch(err => { | ||
// Avoid unneeded warnings: (node:18304) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: ...): ... | ||
console.log(`Avoided UnhandledPromiseRejectionWarning - ${err}`); | ||
}); | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
# core-functions v3.0.2 | ||
# core-functions v3.0.4 | ||
@@ -161,2 +161,20 @@ Core functions, utilities and classes for working with Node/JavaScript primitives and built-in objects, including | ||
### 3.0.4 | ||
- Changes to `promises` module: | ||
- Upgraded to Node 6.10.3 | ||
- Added `avoidUnhandledPromiseRejectionWarning` function to avoid unneeded Node 6.10.3 warnings | ||
- Patched unit tests to pass under Node 6.10.3 | ||
### 3.0.3 | ||
- Minor changes & optimisations to `promises` module: | ||
- Changed `every` & `chain` functions to skip marking internal cancelled flags as true on cancellation if already completed | ||
- Changed `flatten` function to avoid the wasted effort of "flattening" non-Success values and/or arrays of non-Success values | ||
- Changes to `arrays` module: | ||
- Added a `flatten` function | ||
- Changes to `tries` module: | ||
- Changed the default behaviour of the static `countSuccess` & `describeSuccessAndFailureCounts` methods to count any | ||
non-Failure outcomes as successes (instead of ONLY counting Success outcomes as successes) | ||
- Added an optional `strict` argument to these static methods that can be set to true to restore the original | ||
behaviour of ONLY strictly counting Success outcomes as successes | ||
### 3.0.2 | ||
@@ -163,0 +181,0 @@ - Changes to `promises` module: |
@@ -17,2 +17,3 @@ 'use strict'; | ||
const isArrayOfType = Arrays.isArrayOfType; | ||
const flatten = Arrays.flatten; | ||
@@ -27,3 +28,4 @@ function wrap(value) { | ||
return new Boolean(value); | ||
default: return value; | ||
default: | ||
return value; | ||
} | ||
@@ -36,2 +38,3 @@ } | ||
} | ||
// empty array | ||
@@ -55,5 +58,5 @@ check([], true, t); | ||
// arrays of objects | ||
const o1 = {a:1}; | ||
const o2 = {a:1}; | ||
const o3 = {a:1}; | ||
const o1 = {a: 1}; | ||
const o2 = {a: 1}; | ||
const o3 = {a: 1}; | ||
check([o1], true, t); | ||
@@ -91,5 +94,5 @@ check([o1, o2], true, t); | ||
// arrays of objects | ||
const o1 = {a:1}; | ||
const o2 = {a:1}; | ||
const o3 = {a:1}; | ||
const o1 = {a: 1}; | ||
const o2 = {a: 1}; | ||
const o3 = {a: 1}; | ||
check([o1], [o1]); | ||
@@ -110,2 +113,3 @@ check([o1, o2], [o1, o2]); | ||
} | ||
// empty array | ||
@@ -128,3 +132,3 @@ check([], "string", true); | ||
check(['a', 'b', true], "string", false); | ||
check(['a', 'a', {a:'a'}], "string", false); | ||
check(['a', 'a', {a: 'a'}], "string", false); | ||
@@ -140,3 +144,3 @@ // arrays of Strings | ||
check([wrap('a'), wrap('b'), true], String, false); | ||
check([wrap('a'), wrap('a'), {a:wrap('a')}], String, false); | ||
check([wrap('a'), wrap('a'), {a: wrap('a')}], String, false); | ||
@@ -155,3 +159,3 @@ // arrays of both strings and Strings | ||
check([1, 2, '1'], "number", false); | ||
check([1, 1, {a:1}], "number", false); | ||
check([1, 1, {a: 1}], "number", false); | ||
@@ -174,3 +178,3 @@ // arrays of Numbers | ||
check([true, false, 'true'], "boolean", false); | ||
check([true, true, {a:true}], "boolean", false); | ||
check([true, true, {a: true}], "boolean", false); | ||
@@ -185,3 +189,3 @@ // arrays of Booleans | ||
check([wrap(true), wrap(false), 'true'], Boolean, false); | ||
check([wrap(true), wrap(true), {a:wrap(true)}], Boolean, false); | ||
check([wrap(true), wrap(true), {a: wrap(true)}], Boolean, false); | ||
@@ -193,5 +197,5 @@ // arrays of both booleans and Booleans | ||
// arrays of objects | ||
const o1 = {a:1}; | ||
const o2 = {a:1}; | ||
const o3 = {a:1}; | ||
const o1 = {a: 1}; | ||
const o2 = {a: 1}; | ||
const o3 = {a: 1}; | ||
check([o1], Object, true); | ||
@@ -228,1 +232,45 @@ check([o1, o2], Object, true); | ||
test('flatten', t => { | ||
// Empty array | ||
let as = []; | ||
let xs = []; | ||
t.deepEqual(flatten(as), xs, `flatten(${stringify(as)}) must be ${stringify(xs)}`); | ||
// Only non-Array elements | ||
as = [1]; | ||
xs = [1]; | ||
t.deepEqual(flatten(as), xs, `flatten(${stringify(as)}) must be ${stringify(xs)}`); | ||
as = [1, 2]; | ||
xs = [1, 2]; | ||
t.deepEqual(flatten(as), xs, `flatten(${stringify(as)}) must be ${stringify(xs)}`); | ||
as = [1, 2, 3]; | ||
xs = [1, 2, 3]; | ||
t.deepEqual(flatten(as), xs, `flatten(${stringify(as)}) must be ${stringify(xs)}`); | ||
as = [1, 2, 3, 4, 5, 6, 7, 8]; | ||
xs = [1, 2, 3, 4, 5, 6, 7, 8]; | ||
t.deepEqual(flatten(as), xs, `flatten(${stringify(as)}) must be ${stringify(xs)}`); | ||
// Only Array elements | ||
as = [[1], [2]]; | ||
xs = [1, 2]; | ||
t.deepEqual(flatten(as), xs, `flatten(${stringify(as)}) must be ${stringify(xs)}`); | ||
as = [[1, 2], [3, 4], [5, 6, 7], [8]]; | ||
xs = [1, 2, 3, 4, 5, 6, 7, 8]; | ||
t.deepEqual(flatten(as), xs, `flatten(${stringify(as)}) must be ${stringify(xs)}`); | ||
// All Array elements which contain both non-Array & Array elements | ||
as = [[1, [2]], [[3, 4]], [[5, 6], 7], [8]]; | ||
xs = [1, [2], [3, 4], [5, 6], 7, 8]; | ||
t.deepEqual(flatten(as), xs, `flatten(${stringify(as)}) must be ${stringify(xs)}`); | ||
// Mixture of non-Array & Array elements | ||
as = [1, [2], [3, 4], [5, 6], 7, 8]; | ||
xs = [1, 2, 3, 4, 5, 6, 7, 8]; | ||
t.deepEqual(flatten(as), xs, `flatten(${stringify(as)}) must be ${stringify(xs)}`); | ||
t.end(); | ||
}); |
{ | ||
"name": "core-functions-tests", | ||
"version": "3.0.2", | ||
"version": "3.0.4", | ||
"author": "Byron du Preez", | ||
@@ -5,0 +5,0 @@ "license": "Apache-2.0", |
@@ -465,3 +465,9 @@ 'use strict'; | ||
// explicit avoidToJSONMethods must NOT use toJSON method | ||
checkWithOpts(task, {avoidToJSONMethods: true}, wrapInString ? '[object Object]' : '{"name":"Task1","definition":{"name":"Task1","executable":true,"execute":[Function: anonymous],"subTaskDefs":[],"parent":undefined},"executable":true,"execute":[Function: anonymous],"_subTasks":[],"_subTasksByName":{},"parent":undefined,"_state":{"code":"Unstarted","completed":false,"error":undefined,"rejected":false,"reason":undefined},"_attempts":1,"_began":"2016-12-01T05:09:09.119Z","_result":undefined,"_error":undefined,"_slaveTasks":[],"_frozen":true,"toJSON":[Function: toJSON]}'); | ||
if (process && process.version) { | ||
if (process.version.startsWith("4.3.")) { | ||
checkWithOpts(task, {avoidToJSONMethods: true}, wrapInString ? '[object Object]' : '{"name":"Task1","definition":{"name":"Task1","executable":true,"execute":[Function: anonymous],"subTaskDefs":[],"parent":undefined},"executable":true,"execute":[Function: anonymous],"_subTasks":[],"_subTasksByName":{},"parent":undefined,"_state":{"code":"Unstarted","completed":false,"error":undefined,"rejected":false,"reason":undefined},"_attempts":1,"_began":"2016-12-01T05:09:09.119Z","_result":undefined,"_error":undefined,"_slaveTasks":[],"_frozen":true,"toJSON":[Function: toJSON]}'); | ||
} else if (process.version.startsWith("6.10.")) { | ||
checkWithOpts(task, {avoidToJSONMethods: true}, wrapInString ? '[object Object]' : '{"name":"Task1","definition":{"name":"Task1","executable":true,"execute":[Function: execute],"subTaskDefs":[],"parent":undefined},"executable":true,"execute":[Function: execute],"_subTasks":[],"_subTasksByName":{},"parent":undefined,"_state":{"code":"Unstarted","completed":false,"error":undefined,"rejected":false,"reason":undefined},"_attempts":1,"_began":"2016-12-01T05:09:09.119Z","_result":undefined,"_error":undefined,"_slaveTasks":[],"_frozen":true,"toJSON":[Function: toJSON]}'); | ||
} | ||
} | ||
} | ||
@@ -468,0 +474,0 @@ |
23
tries.js
@@ -155,8 +155,11 @@ 'use strict'; | ||
/** | ||
* Returns a count of the number of Success outcomes in the given list of outcomes. | ||
* @param {Outcomes} outcomes - a list of outcomes | ||
* @returns {number} the number of Success outcomes | ||
* Returns a count of the number of Success outcomes (if strict) or non-Failure outcomes (if not strict) in the given | ||
* list of outcomes. | ||
* @param {Outcomes|*[]} outcomes - a list of outcomes | ||
* @param {boolean|undefined} [strict] - whether to strictly count ONLY Success outcomes as successes (if true) or count any non-Failure outcomes as successes (if not true - default) | ||
* @returns {number} the number of Success or non-Failure outcomes | ||
*/ | ||
static countSuccess(outcomes) { | ||
return outcomes.reduce((acc, o) => acc + (o instanceof Success ? 1 : 0), 0); | ||
static countSuccess(outcomes, strict) { | ||
const isSuccess = strict ? o => o instanceof Success : o => !(o instanceof Failure); | ||
return outcomes.reduce((acc, o) => acc + (isSuccess(o) ? 1 : 0), 0); | ||
} | ||
@@ -175,7 +178,8 @@ | ||
* Returns a description of the number of successes followed by the number of failures in the given list of outcomes. | ||
* @param {Outcomes} outcomes - a list of outcomes | ||
* @returns {string} the number of Failure outcomes | ||
* @param {Outcomes|*[]} outcomes - a list of outcomes (or of any results) | ||
* @param {boolean|undefined} [strict] - whether to strictly count ONLY Success outcomes as successes (if true) or count any non-Failure outcomes as successes (if not true - default) | ||
* @returns {string} a description of the number of successes and the number of failures | ||
*/ | ||
static describeSuccessAndFailureCounts(outcomes) { | ||
const successCount = Try.countSuccess(outcomes); | ||
static describeSuccessAndFailureCounts(outcomes, strict) { | ||
const successCount = Try.countSuccess(outcomes, strict); | ||
const failureCount = Try.countFailure(outcomes); | ||
@@ -283,3 +287,2 @@ return `${successCount} success${successCount !== 1 ? 'es' : ''} & ${failureCount} failure${failureCount !== 1 ? 's' : ''}`; | ||
} | ||
// return value instanceof Failure ? value : undefined; | ||
return undefined; | ||
@@ -286,0 +289,0 @@ } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
909530
14452
422