core-functions
Advanced tools
Comparing version 3.0.23 to 3.0.24
## Changes | ||
### 3.0.24 | ||
- Changes to `promises` module: | ||
- Changed `wrap` & `wrapMethod` functions to handle successful callbacks with more than 2 arguments by resolving the | ||
promise with an array containing all of the arguments other than the first. Note that successful callbacks with only | ||
2 arguments will still return the 2nd argument as before (instead of an array containing only the 2nd argument). | ||
- Changed `wrap` & `wrapMethod` functions to timeout and reject their promises if they are still pending after a | ||
configurable number of milliseconds - to avoid cases where the wrapped function does NOT call the callback. | ||
- Added new optional `opts` last argument to `wrap` & `wrapMethod` functions to enable configuration of the timeout | ||
time in milliseconds | ||
### 3.0.23 | ||
@@ -4,0 +14,0 @@ - Added `.npmignore` |
{ | ||
"name": "core-functions", | ||
"version": "3.0.23", | ||
"version": "3.0.24", | ||
"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.", | ||
@@ -14,5 +14,5 @@ "author": "Byron du Preez", | ||
"devDependencies": { | ||
"tape": "^4.9.0" | ||
"tape": "^4.9.1" | ||
}, | ||
"repository": "https://github.com/byron-dupreez/core-functions" | ||
} |
115
promises.js
@@ -10,2 +10,3 @@ 'use strict'; | ||
const TimeoutError = require('./errors').TimeoutError; | ||
@@ -40,2 +41,15 @@ /** | ||
/** | ||
* The default number of milliseconds to wait for a wrapped function/method call to complete before timing out. | ||
* @type {number} | ||
*/ | ||
const defaultWrappedCallTimeoutInMs = 120000; // defaults to 2 minutes | ||
/** | ||
* Default options to use with the `wrap` & `wrapMethod` functions. | ||
* @type {{timeoutMs: number}} | ||
*/ | ||
const defaultWrapOpts = {timeoutMs: defaultWrappedCallTimeoutInMs}; | ||
exports.defaultWrapOpts = defaultWrapOpts; | ||
/** | ||
* Sample options to use to alter the behaviour of the `flatten` function | ||
@@ -160,4 +174,10 @@ * @namespace {Object.<string,FlattenOpts} | ||
* | ||
* NB: This function must be passed a Node-style function that accepts as its last parameter a Node-style callback that | ||
* in turn accepts 2 parameters: error; and data. | ||
* NB: This function must be passed a Node-style function that accepts as its last parameter a Node-style callback | ||
* that in turn accepts 2 (or more) parameters: | ||
* 1. An optional error (1st parameter), which indicates failure; | ||
* 2. An optional value (2nd parameter), which indicates success when error is not defined; and | ||
* 3. Optionally more success values (3rd to Nth parameters, where N is the total number of parameters passed). | ||
* NB: If the 1st parameter is null and more than 2 parameters are passed to the Node-style callback then the returned | ||
* promise will resolve with an array containing the 2nd to Nth parameters instead of simply resolving with the 2nd | ||
* parameter in order to preserve the 3rd to Nth parameters. | ||
* | ||
@@ -244,7 +264,11 @@ * Borrowed and slightly tweaked from "You don't know JavaScript - Async & Performance" (thanks Kyle Simpson) | ||
* @param {Function} fn - a Node-callback style function to "promisify" | ||
* @param {WrapOpts} [opts] - optional options to use to configure the wrapping (defaults to defaultWrapOpts) | ||
* @returns {function(...args: *): Promise.<R>} a function, which when invoked will return a new Promise that will | ||
* resolve or reject based on the outcome of the callback | ||
* resolve or reject based on the outcome of the callback | ||
* @template R | ||
*/ | ||
function wrap(fn) { | ||
function wrap(fn, opts = defaultWrapOpts) { | ||
if (typeof fn !== 'function') throw new TypeError(`Promises.wrap(fn) - fn must be a function`); | ||
const timeoutMs = opts && opts.timeoutMs || defaultWrappedCallTimeoutInMs; | ||
return function () { | ||
@@ -260,9 +284,33 @@ const self = this; | ||
return new Promise((resolve, reject) => { | ||
args[len] = (err, v) => { | ||
if (err) reject(err); | ||
else resolve(v); | ||
}; | ||
let done = false; | ||
let timedOut = false; | ||
const timeout = setTimeout(() => { | ||
if (!done) { | ||
timedOut = true; | ||
reject(new TimeoutError(`Timed out while waiting ${timeoutMs} ms for callback from wrapped '${fn.name}' function`)); | ||
} | ||
}, timeoutMs); | ||
args[len] = (err, v, ...rest) => { | ||
if (!timedOut) { | ||
done = true; | ||
try { | ||
clearTimeout(timeout); | ||
} catch (e) { | ||
console.error(`Failed to clear timeout for wrapped '${fn.name}' function`, e); | ||
} finally { | ||
if (err) reject(err); | ||
else resolve(rest.length <= 0 ? v : [v].concat(rest)); | ||
} | ||
} | ||
}; | ||
try { | ||
fn.apply(self, args); | ||
} catch (err) { | ||
console.error(`Wrapped '${fn.name}' function threw:`, err); | ||
reject(err); // for backward compatibility | ||
} | ||
); | ||
}); | ||
}; | ||
@@ -301,2 +349,3 @@ } | ||
* @param {Function} method - a Node-callback style method (of the given object) to promisify | ||
* @param {WrapOpts} [opts] - optional options to use to configure the wrapping (defaults to defaultWrapOpts) | ||
* @returns {function(...args: *): Promise.<R>} a function, which when invoked will return a new Promise that will | ||
@@ -306,3 +355,7 @@ * resolve or reject based on the outcome of the callback | ||
*/ | ||
function wrapMethod(obj, method) { | ||
function wrapMethod(obj, method, opts = defaultWrapOpts) { | ||
if (!obj || typeof obj !== 'object') throw new TypeError(`Promises.wrapMethod(obj, method) - obj must be a non-null object`); | ||
if (typeof method !== 'function') throw new TypeError(`Promises.wrapMethod(obj, method) - method must be a function`); | ||
const timeoutMs = opts && opts.timeoutMs || defaultWrappedCallTimeoutInMs; | ||
return function () { | ||
@@ -317,9 +370,33 @@ //const args = [].slice.call( arguments ); | ||
return new Promise((resolve, reject) => { | ||
args[len] = (err, v) => { | ||
if (err) reject(err); | ||
else resolve(v); | ||
}; | ||
let done = false; | ||
let timedOut = false; | ||
const timeout = setTimeout(() => { | ||
if (!done) { | ||
timedOut = true; | ||
reject(new TimeoutError(`Timed out while waiting ${timeoutMs} ms for callback from wrapped '${method.name}' method`)); | ||
} | ||
}, timeoutMs); | ||
args[len] = (err, v, ...rest) => { | ||
if (!timedOut) { | ||
done = true; | ||
try { | ||
clearTimeout(timeout); | ||
} catch (e) { | ||
console.error(`Failed to clear timeout for wrapped '${method.name}' method`, e); | ||
} finally { | ||
if (err) reject(err); | ||
else resolve(rest.length <= 0 ? v : [v].concat(rest)); | ||
} | ||
} | ||
}; | ||
try { | ||
method.apply(obj, args); | ||
} catch (err) { | ||
console.error(`Wrapped '${method.name}' method threw:`, err); | ||
reject(err); // for backward compatibility | ||
} | ||
); | ||
}); | ||
} | ||
@@ -334,7 +411,11 @@ } | ||
* @param {string} methodName - the name of a Node callback-last style method (of the given object) to promisify | ||
* @param {WrapOpts} [opts] - optional options to use to configure the wrapping (defaults to {timeoutMs: 60000}) | ||
* @returns {function(...args: *): Promise.<R>} | ||
* @template R | ||
*/ | ||
function wrapNamedMethod(obj, methodName) { | ||
return wrapMethod(obj, obj[methodName]); | ||
function wrapNamedMethod(obj, methodName, opts = defaultWrapOpts) { | ||
if (!obj || typeof obj !== 'object') throw new TypeError(`Promises.wrapNamedMethod(obj, methodName) - obj must be a non-null object`); | ||
const method = obj[methodName]; | ||
if (typeof method !== 'function') throw new TypeError(`Promises.wrapNamedMethod(obj, methodName) - obj[methodName] must be a function`); | ||
return wrapMethod(obj, method, opts); | ||
} | ||
@@ -341,0 +422,0 @@ |
@@ -1,2 +0,2 @@ | ||
# core-functions v3.0.23 | ||
# core-functions v3.0.24 | ||
@@ -3,0 +3,0 @@ Core functions, utilities and classes for working with Node/JavaScript primitives and built-in objects, including |
@@ -223,2 +223,8 @@ /** | ||
* @property {boolean|undefined} [keepFailures] - if true, collects and preserves any Failure outcomes as is; otherwise flattens Failures too and throws the error of the first Failure found (defaults to false) | ||
*/ | ||
/** | ||
* @typedef {Object} WrapOpts - optional options to use with the promisify functions (i.e. `wrap` & `wrapMethod` functions of the promises module) | ||
* @property {number|undefined} [timeoutMs] - the optional number of milliseconds to wait before timing out the | ||
* returned promise to avoid never-ending promise issues when the callback is never invoked (defaults to 60s) | ||
*/ |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
265592
24
4415
0