Comparing version 15.0.0-1 to 15.0.0-2
585
index.js
@@ -5,439 +5,240 @@ /** | ||
var util = require('util'); | ||
var _ = require('@sailshq/lodash'); | ||
var flaverr = require('flaverr'); | ||
var parley = require('parley'); | ||
var build = require('./lib/build'); | ||
var getMethodName = require('./lib/get-method-name'); | ||
var pack = require('./lib/pack'); | ||
var RELEASE_LICENSE = require('./package.json').license; | ||
var RELEASE_SERIES = 'gen2'; | ||
var RELEASE_VERSION = require('./package.json').version; | ||
/** | ||
* `buildCallableMachine()` | ||
* Machine() | ||
* | ||
* Build a callable ("wet") machine. | ||
* | ||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
* @param {Dictionary} nmDef | ||
* A Node-Machine definition. | ||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
* @returns {Function} | ||
* A callable, "wet" machine. | ||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
* @type {Function} | ||
* @properties | ||
* .build() | ||
* .buildWithCustomUsage() | ||
* .pack() | ||
* .getMethodName() | ||
*/ | ||
module.exports = function buildCallableMachine(nmDef){ | ||
module.exports = build; | ||
// Determine the effective identity of this machine. | ||
var identity;//TODO | ||
// Verify correctness of node-machine definition. | ||
// TODO | ||
// Sanitize input definitions. | ||
// var inputDefs = nmDef.inputs || {}; | ||
// TODO | ||
// ███████╗████████╗ █████╗ ████████╗██╗ ██████╗ ███╗ ███╗███████╗████████╗██╗ ██╗ ██████╗ ██████╗ ███████╗ | ||
// ██╔════╝╚══██╔══╝██╔══██╗╚══██╔══╝██║██╔════╝ ████╗ ████║██╔════╝╚══██╔══╝██║ ██║██╔═══██╗██╔══██╗██╔════╝ | ||
// ███████╗ ██║ ███████║ ██║ ██║██║ ██╔████╔██║█████╗ ██║ ███████║██║ ██║██║ ██║███████╗ | ||
// ╚════██║ ██║ ██╔══██║ ██║ ██║██║ ██║╚██╔╝██║██╔══╝ ██║ ██╔══██║██║ ██║██║ ██║╚════██║ | ||
// ███████║ ██║ ██║ ██║ ██║ ██║╚██████╗ ██║ ╚═╝ ██║███████╗ ██║ ██║ ██║╚██████╔╝██████╔╝███████║ | ||
// ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ | ||
// | ||
// Sanitize exit definitions. | ||
var exitDefs = nmDef.exits || {}; | ||
exitDefs.success = exitDefs.success || {}; | ||
exitDefs.error = exitDefs.error || {}; | ||
// TODO | ||
// Check `sync`. | ||
// TODO | ||
/** | ||
* .getMethodName() | ||
* | ||
* See lib/get-method-name.js | ||
*/ | ||
module.exports.getMethodName = getMethodName; | ||
// Check `timeout`. | ||
// TODO | ||
// Return our callable ("wet") machine function in the appropriate format. | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// FUTURE: Consider support for returning a machine function with other usage styles | ||
// For example, instead of: | ||
// | ||
// ``` | ||
// var add = Machine.build(nmDef); | ||
// // ... | ||
// var result = add({a:1,b:1}).execSync(); | ||
// ``` | ||
// | ||
// You could do: | ||
// ``` | ||
// var add = Machine.buildWithCustomUsage({ | ||
// arginStyle: 'serial', | ||
// def: _.extend({ args: ['a','b'] }, nmDef) | ||
// }); | ||
// // ... | ||
// var result = add(1,2).execSync(); | ||
// ``` | ||
// | ||
// Or even: | ||
// ``` | ||
// var add = Machine.buildWithCustomUsage({ | ||
// arginStyle: 'serial', // vs. "named" | ||
// execStyle: 'immediate', // vs. "deferred" | ||
// def: _.extend({ args: ['a','b'] }, nmDef) | ||
// }); | ||
// // ... | ||
// var result = add(1,2); | ||
// ``` | ||
// | ||
// Same idea for asynchronous logic: | ||
// (using the `immediate` exec style, a promise is returned, instead of the actual result) | ||
// ``` | ||
// var fetchTweets = Machine.buildWithCustomUsage({ | ||
// arginStyle: 'serial', // vs. "named" | ||
// execStyle: 'immediate', // vs. "deferred" | ||
// def: _.extend({ | ||
// args: [ | ||
// [ 'tweetSearchQuery','done()' ], | ||
// [ 'tweetSearchQuery','{...}', 'done()' ] | ||
// ] | ||
// }, nmDef) | ||
// }); | ||
// // ... | ||
// var result = await fetchTweets('twinkle', {lat: 37.2332, long: -92.323852}); | ||
// ``` | ||
// | ||
// One more example: | ||
// ``` | ||
// var fetchTweets = Machine.buildWithCustomUsage({ | ||
// arginStyle: 'named', // vs. "serial" | ||
// execStyle: 'immediate', // vs. "deferred" | ||
// def: _.extend({ | ||
// args: [ | ||
// [ 'tweetSearchQuery','done()' ], | ||
// [ 'tweetSearchQuery','{...}', 'done()' ] | ||
// ] | ||
// }, nmDef) | ||
// }); | ||
// // ... | ||
// var result = await fetchTweets({ | ||
// tweetSearchQuery: 'twinkle', | ||
// lat: 37.2332, | ||
// long: -92.323852 | ||
// }); | ||
// ``` | ||
// | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
return function runFn(argins, explicitCbMaybe, metadata){ | ||
/** | ||
* .pack() | ||
* | ||
* See lib/pack.js | ||
*/ | ||
module.exports.pack = pack; | ||
// Tolerate a few alternative usages: | ||
// • `runFn(function(err, result){...})` | ||
// • `runFn(function(err, result){...}, {...})` | ||
if (_.isFunction(argins) && _.isUndefined(explicitCbMaybe)) { | ||
metadata = explicitCbMaybe; | ||
explicitCbMaybe = argins; | ||
}//>- | ||
// Tolerate unspecified argins: | ||
if (_.isUndefined(argins)) { | ||
argins = {}; | ||
}//>- | ||
// Handle unspecified metadata -- the usual case | ||
// (these are fka habitat vars) | ||
if (_.isUndefined(metadata)) { | ||
metadata = {}; | ||
}//>- | ||
// Check usage. | ||
if (!_.isObject(argins) && _.isFunction(argins) && _.isArray(argins)) { | ||
throw flaverr({name:'UsageError'}, new Error( | ||
'Sorry, this function doesn\'t know how to handle usage like that.\n'+ | ||
'If provided, the 1st argument should be a dictionary like `{...}`\n'+ | ||
'consisting of input values (aka "argins") to pass through to the fn.\n'+ | ||
'> See https://sailsjs.com/support for help.' | ||
)); | ||
} | ||
if (!_.isUndefined(explicitCbMaybe) && !_.isFunction(explicitCbMaybe)) { | ||
throw flaverr({name:'UsageError'}, new Error( | ||
'Sorry, this function doesn\'t know how to handle usage like that.\n'+ | ||
'If provided, the 2nd argument should be a function like `function(err,result){...}`\n'+ | ||
'that will be triggered as a callback after this fn is finished.\n'+ | ||
'> See https://sailsjs.com/support for help.' | ||
)); | ||
} | ||
// Build an "omen": an Error instance defined ahead of time in order to grab a stack trace. | ||
// (used for providing a better experience when viewing the stack trace of errors | ||
// that come from one or more asynchronous ticks down the line; e.g. uniqueness errors) | ||
// | ||
// Remember that this omen can only be used as an Error ONCE! | ||
// | ||
// > Inspired by the implementation originally devised for Waterline: | ||
// > https://github.com/balderdashy/waterline/blob/6b1f65e77697c36561a0edd06dff537307986cb7/lib/waterline/utils/query/build-omen.js | ||
var omen = flaverr({}, new Error('omen'), runFn); | ||
/** | ||
* .VERSION | ||
* .version | ||
* | ||
* @type {String} | ||
*/ | ||
module.exports.VERSION = RELEASE_VERSION; | ||
module.exports.version = RELEASE_VERSION; | ||
// Build and return an appropriate deferred object. | ||
// (Or possibly just start executing the machine immediately, depending on usage) | ||
return parley( | ||
function (done){ | ||
// Now actually run the machine, in whatever way is appropriate based on its implementation type. | ||
switch (nmDef.implementationType) { | ||
/** | ||
* .inspect() | ||
* | ||
* When the Machine constructor is inspected (e.g. `util.inspect()` / `console.log()`), | ||
* pretty print the current version of node-machine, with license information and a link | ||
* to the documentation. | ||
* | ||
* @returns {String} | ||
*/ | ||
module.exports.inspect = function () { | ||
return ''+ | ||
'---------------------------------------------------\n'+ | ||
' machine'+/*' (runtime environment)'+*/'\n'+ | ||
' v'+RELEASE_VERSION+' ('+RELEASE_SERIES+')\n'+ | ||
' \n'+ | ||
' • License : '+RELEASE_LICENSE+'\n'+ | ||
' • Package : http://npmjs.com/package/machine\n'+ | ||
' • Questions : https://sailsjs.com/studio\n'+ | ||
'---------------------------------------------------\n'; | ||
}; | ||
case 'composite': | ||
return done(flaverr({name:'UsageError'}, new Error('Machines built with the `composite` implementation type cannot be executed using this runner. (For help, visit https://sailsjs.com/support)'))); | ||
case 'classic': | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// FUTURE: Support automatically mapping this usage to the "classic" implementation type: | ||
// (see https://github.com/node-machine/spec/pull/2/files#diff-eba3c42d87dad8fb42b4080df85facecR95) | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
return done(flaverr({name:'UsageError'}, new Error('The `classic` implementation type is experimental, and not yet supported. See https://github.com/node-machine/spec/pull/2/files#diff-eba3c42d87dad8fb42b4080df85facecR95 for background, or https://sailsjs.com/support for help.'))); | ||
/** | ||
* .build() | ||
* | ||
* Build a wet (callable) machine. | ||
* | ||
* @returns {Function} | ||
*/ | ||
module.exports.build = function(){ | ||
// console.warn('WARNING: As of v15, machine should be called directly instead of using `.build()`. (Adjusting for you this time...)'); | ||
return this.apply(undefined, arguments); | ||
}; | ||
default: | ||
/** | ||
* .buildWithCustomUsage() | ||
* | ||
* Return a machine function with a custom usage style. | ||
* | ||
* @property {Dictionary} def | ||
* @property {String?} arginStyle ("named" or "serial") | ||
* @property {String?} execStyle ("deferred" or "immediate") | ||
*/ | ||
module.exports.buildWithCustomUsage = function (opts) { | ||
var finalArgins = argins; | ||
// Validate argins vs. our declared input definitions. | ||
// (Potentially, also coerce them.) | ||
// TODO | ||
// Verify correctness of node-machine definition. | ||
var nmDef = opts.def;// TODO | ||
// Build callable forms of lambda inversions (aka submachines) | ||
// TODO | ||
// FUTURE: Reject unrecognized opts to help avoid misunderstandings in userland code | ||
// Run `fn`. | ||
// | ||
// > Note: When running our fn, we apply a special `this` context | ||
// > using the provided meta keys (aka habitat vars) | ||
_.bind(nmDef.fn, metadata)( | ||
var arginStyle = opts.arginStyle || 'named'; | ||
var execStyle = opts.execStyle || 'deferred'; | ||
finalArgins, | ||
return function (){ | ||
(function _gettingHandlerCbs(){ | ||
var argins = {}; | ||
switch (arginStyle) { | ||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// | ||
// USAGE: Node-style callback, or with a promise, or with async...await | ||
// (note that, when leveraging switchbacks, there are slightly different rules) | ||
// | ||
// _______________________________________________________________________________________________________________________________________________________________________________________________________________________________________ | ||
// || exit => | 'error' (explicit) | 'error' (throw) | 'error' (timeout) | 'error' (validation) | misc. exit | misc. exit | success | success | | ||
// \/ output | `exits.error()` | `throw new Error()` | | | (NOT expecting output) | (EXPECTING output) | (NOT expecting output) | (EXPECTING output) | | ||
// ______________________|_________________________|_________________________|_________________________|_________________________|_________________________|_________________________|_________________________|_________________________| | ||
// Error instance | pass straight through | pass straight through | N/A - always an Error | N/A - always an Error | pass straight through | coerce | pass straight through | coerce | | ||
// | | (handled by parley) | (handled by parley) | | | | | | | ||
// ----------------------| -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | | ||
// String data | new Error w/ str as msg | new Error w/ str as msg | N/A - always an Error | N/A - always an Error | new Error w/ str as msg | coerce | pass straight through | coerce | | ||
// | | | (handled by parley) | | | | | | | ||
// ----------------------| -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | | ||
// Other non-Error data | new Error + wrap output | new Error + wrap output | N/A - always an Error | N/A - always an Error | new Error + wrap output | coerce | pass straight through | coerce | | ||
// | | | (handled by parley) | | | | | | | ||
// ----------------------| -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | -- -- -- -- -- -- | | ||
// No output (undefined) | new Error, generic | new Error, generic | N/A - always an Error | N/A - always an Error | new Error, w/ descrptn. | coerce | pass straight through | coerce | | ||
// | | | (handled by parley) | | | | | | | ||
// _______________________________________________________________________________________________________________________________________________________________________________________________________________________________________ | ||
// | ||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
case 'named': | ||
argins = arguments[0]; | ||
break; | ||
// Build & return exit handler callbacks for use by the machine's `fn`. | ||
var handlerCbs = function (){ throw flaverr({name:'CompatibilityError'}, new Error('Implementor-land switchbacks are no longer supported by default in the machine runner. Instead of `exits()`, please call `exits.success()` or `exits.error()` from within your machine `fn`. (For help, visit https://sailsjs.com/support)')); }; | ||
(function _attachingHandlerCbs(proceed){ | ||
handlerCbs.error = function(rawOutput){ | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// FUTURE: Consider implementing backwards compatibility for a `code` of `E_TIMEOUT`? | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// FUTURE: Consider implementing backwards compatibility for a `code` of `E_MACHINE_RUNTIME_VALIDATION`? | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// Ensure that the catchall error exit (`error`) always comes back with an Error instance | ||
// (i.e. so node callback expectations are fulfilled) | ||
var err; | ||
if (_.isUndefined(rawOutput)) { | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// FUTURE: Consider actually NOT using the omen in this case -- since we might | ||
// be interested in the line of code where the `exits.error()` was called. | ||
// OR, better yet, still use the omen, but also capture an additional trace | ||
// and attach it as an extra property. (**We might actually consider doing the | ||
// same thing for a few of the other cases below!**) | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
err = flaverr({ | ||
message: 'Internal error occurred while running `'+identity+'`.' | ||
}, omen); | ||
} | ||
else if (_.isError(rawOutput)) { | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// FUTURE: Consider this: Imagine we checked the Error instance to see if it has a | ||
// `code` or `name` that indicates any special meaning -- whether that be a `name` | ||
// of `RuntimeValidationError`/ `TimeoutError`, or just a `code` that happens to | ||
// overlap with the name of one of this machine's declared exits. In either of these | ||
// cases, we might strip that information off and preserve it instead. | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
err = rawOutput; | ||
} | ||
else if (_.isString(rawOutput)) { | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// FUTURE: add in separate warning message explaining that there should always | ||
// be an Error instance sent back -- not some other value like this. | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
err = flaverr({ | ||
message: rawOutput, | ||
raw: rawOutput | ||
}, omen); | ||
} | ||
else { | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// FUTURE: add in separate warning message explaining that there should always | ||
// be an Error instance sent back -- not some other value like this. | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
err = flaverr({ | ||
message: 'Internal error occurred while running `'+identity+'`. Got non-error: '+util.inspect(rawOutput, {depth: 5}), | ||
raw: rawOutput | ||
}, omen); | ||
} | ||
return proceed(err); | ||
}; | ||
handlerCbs.success = function(rawOutput){ | ||
// Ensure valid result (vs. expected output type for this exit) | ||
var result = rawOutput;//TODO | ||
return proceed(undefined, result); | ||
}; | ||
_.each(_.difference(_.keys(exitDefs), ['error','success']), function (miscExitCodeName){ | ||
handlerCbs[miscExitCodeName] = function (rawOutput){ | ||
// Now build our Error instance for our "exception" (fka "forwarding error"). | ||
var err = flaverr({ | ||
name: 'Exception', | ||
code: miscExitCodeName, | ||
raw: rawOutput, | ||
message: (function _gettingErrMsg(){ | ||
// The error msg always begins with a standard prefix: | ||
var errMsg = '`'+identity+'` triggered its `'+miscExitCodeName+'` exit'; | ||
// And is then augmented by some additional basic rules: | ||
// • if there is no raw output, append the exit description if available. | ||
if (_.isUndefined(rawOutput)) { | ||
if (!_.isObject(exitDefs[miscExitCodeName])) { throw new Error('Consistency violation: Machine ('+identity+') has become corrupted! One of its exits (`'+miscExitCodeName+'`) has gone missing _while the machine was being executed_!'); } | ||
if (exitDefs[miscExitCodeName].description) { | ||
errMsg += ': '+exitDefs[miscExitCodeName].description; | ||
} | ||
} | ||
// • if the raw output is an Error instance, then just append _its_ message | ||
else if (_.isError(rawOutput)) { | ||
errMsg += ': '+rawOutput.message; | ||
} | ||
// • if the raw output is anything else, inspect and append it | ||
else if (!_.isError(rawOutput)) { | ||
errMsg += ' with: \n\n' + util.inspect(rawOutput, {depth: 5}); | ||
} | ||
return errMsg; | ||
})(), | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// FUTURE: Potentially also add backwards-compatibility: | ||
// ``` | ||
// exit: miscExitCodeName, | ||
// output: rawOutput, | ||
// ``` | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
}, omen); | ||
return proceed(err); | ||
}; | ||
});//</ each misc. exit > | ||
})(function (err, result){ | ||
// Then trigger our callback with the appropriate arguments. | ||
if (err) { return done(err); } | ||
if (_.isUndefined(result)) { return done(); } | ||
return done(undefined, result); | ||
});//</ ... > | ||
return handlerCbs; | ||
})(), | ||
(function _gettingHabitatVars() { | ||
return metadata; | ||
})() | ||
); | ||
}//</ switch > | ||
}, | ||
// If provided, use the explicit callback. | ||
explicitCbMaybe || undefined, | ||
// Extra methods for the Deferred: | ||
{ | ||
execSync: function (){ | ||
// throw new Error('TODO'); | ||
// TODO: Finish implementing this properly, including the various checks & balances. | ||
var immediateResult; | ||
this.exec(function (err, result){ | ||
if (err) { throw err; } | ||
immediateResult = result; | ||
}); | ||
return immediateResult; | ||
}, | ||
meta: function (_metadata){ | ||
metadata = _metadata; | ||
return this; | ||
}, | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// TODO: figure out how/if we're going to support userland switchbacks going forward. | ||
// (likely it won't be more than just simple backwards compatibility, and it'll | ||
// probably be implemented here, rather than in parley, to avoid problems) | ||
// e.g. | ||
case 'serial': | ||
_.each(arguments, function(argin, i){ | ||
var supposedInputName = nmDef.args[i]; | ||
argins[supposedInputName] = argin; | ||
}); | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// FUTURE: Consider more full-featured support for serial args by using smarter arg-reading logic | ||
// and supporting a richer symbol language in the `args` prop on machine defs. | ||
// | ||
// > Note: This is the same idea as "invocation style" or "invocation type" -- i.e. as envisioned | ||
// > for performance improvements when ideating with jdalton earlier in 2017 (see node-machine/spec | ||
// > repo for details/memory-jogging) | ||
// | ||
// For example, instead of: | ||
// | ||
// ``` | ||
// .switch({ | ||
// error: function(err){...}, | ||
// foo: function(){...}, | ||
// success: function(){...} | ||
// }) | ||
// var add = Machine.build(nmDef); | ||
// // ... | ||
// var result = add({a:1,b:1}).execSync(); | ||
// ``` | ||
// switch: function (handlers) { | ||
// if (!handlers.error) { TODO freak out } | ||
// // etc | ||
// this.exec(function (err, result){ | ||
// // TODO | ||
// }); | ||
// }, | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
// | ||
// You could do: | ||
// ``` | ||
// var add = Machine.buildWithCustomUsage({ | ||
// arginStyle: 'serial', | ||
// def: _.extend({ args: ['a','b'] }, nmDef) | ||
// }); | ||
// // ... | ||
// var result = add(1,2).execSync(); | ||
// ``` | ||
// | ||
// Or even: | ||
// ``` | ||
// var add = Machine.buildWithCustomUsage({ | ||
// arginStyle: 'serial', // vs. "named" | ||
// execStyle: 'immediate', // vs. "deferred" | ||
// def: _.extend({ args: ['a','b'] }, nmDef) | ||
// }); | ||
// // ... | ||
// var result = add(1,2); | ||
// ``` | ||
// | ||
// Same idea for asynchronous logic: | ||
// (using the `immediate` exec style, a promise is returned, instead of the actual result) | ||
// ``` | ||
// var fetchTweets = Machine.buildWithCustomUsage({ | ||
// arginStyle: 'serial', // vs. "named" | ||
// execStyle: 'immediate', // vs. "deferred" | ||
// def: _.extend({ | ||
// args: [ | ||
// [ 'tweetSearchQuery','done()' ], | ||
// [ 'tweetSearchQuery','{...}', 'done()' ] | ||
// ] | ||
// }, nmDef) | ||
// }); | ||
// // ... | ||
// var result = await fetchTweets('twinkle', {lat: 37.2332, long: -92.323852}); | ||
// ``` | ||
// | ||
// One more example: | ||
// ``` | ||
// var fetchTweets = Machine.buildWithCustomUsage({ | ||
// arginStyle: 'named', // vs. "serial" | ||
// execStyle: 'immediate', // vs. "deferred" | ||
// def: _.extend({ | ||
// args: [ | ||
// [ 'tweetSearchQuery','done()' ], | ||
// [ 'tweetSearchQuery','{...}', 'done()' ] | ||
// ] | ||
// }, nmDef) | ||
// }); | ||
// // ... | ||
// var result = await fetchTweets({ | ||
// tweetSearchQuery: 'twinkle', | ||
// lat: 37.2332, | ||
// long: -92.323852 | ||
// }); | ||
// ``` | ||
// | ||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
break; | ||
setEnv: function (_metadata) { | ||
console.warn( | ||
'DEPRECATED AS OF MACHINE v15: Please use `.meta()` instead of `.setEnv()` in the future\n'+ | ||
'(adjusting it for you automatically this time)\n' | ||
); | ||
return this.meta(_metadata); | ||
}, | ||
default: | ||
throw flaverr({name:'UsageError'}, new Error('Unrecognized arginStyle: "'+arginStyle+'"')); | ||
} | ||
}, | ||
var basicRunner = module.exports.build(nmDef); | ||
var deferredObj = basicRunner(argins); | ||
// If provided, use the timeout (max # of ms to wait for this machine to finish executing) | ||
nmDef.timeout || undefined, | ||
switch (execStyle) { | ||
// Pass in the omen, if we were able to create one. | ||
omen || undefined | ||
case 'deferred': | ||
return deferredObj; | ||
); | ||
case 'immediate': | ||
if (nmDef.sync) { | ||
return deferredObj.execSync(); | ||
} | ||
else { | ||
return deferredObj.toPromise(); | ||
} | ||
};//</ return > | ||
default: | ||
throw flaverr({name:'UsageError'}, new Error('Unrecognized execStyle: "'+execStyle+'"')); | ||
}; | ||
} | ||
}; | ||
// ██████╗ ██████╗ ███╗ ███╗██████╗ █████╗ ████████╗██╗██████╗ ██╗██╗ ██╗████████╗██╗ ██╗ | ||
// ██╔════╝██╔═══██╗████╗ ████║██╔══██╗██╔══██╗╚══██╔══╝██║██╔══██╗██║██║ ██║╚══██╔══╝╚██╗ ██╔╝██╗ | ||
// ██║ ██║ ██║██╔████╔██║██████╔╝███████║ ██║ ██║██████╔╝██║██║ ██║ ██║ ╚████╔╝ ╚═╝ | ||
// ██║ ██║ ██║██║╚██╔╝██║██╔═══╝ ██╔══██║ ██║ ██║██╔══██╗██║██║ ██║ ██║ ╚██╔╝ ██╗ | ||
// ╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ██║ ██║ ██║ ██║██████╔╝██║███████╗██║ ██║ ██║ ╚═╝ | ||
// ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═════╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ | ||
// | ||
// Compatibility: | ||
// ===================================================================================================================== | ||
module.exports.build = function(){ | ||
console.warn('WARNING: As of v15, machine should be called directly instead of using `.build()`. (Adjusting for you this time...)'); | ||
return module.exports.apply(undefined, arguments); | ||
}; | ||
module.exports.pack = function(){ | ||
throw flaverr({name:'CompatibilityError'}, new Error('As of machine v15, `.pack()` is no longer supported. Instead, please use `require(\'machinepack\')`.')); | ||
}; |
{ | ||
"name": "machine", | ||
"version": "15.0.0-1", | ||
"version": "15.0.0-2", | ||
"description": "Build functions in standardized containers.", | ||
@@ -40,3 +40,3 @@ "keywords": [ | ||
"parley": "^2.4.0-0", | ||
"rttc": "^9.8.1" | ||
"rttc": "^10.0.0-1" | ||
}, | ||
@@ -43,0 +43,0 @@ "devDependencies": { |
@@ -67,3 +67,4 @@ /** | ||
} catch (e) { | ||
if (e.code === 'E_NO_ERROR_CALLBACK_CONFIGURED') { | ||
// (Note: In past versions, this was indicated by a code of 'E_NO_ERROR_CALLBACK_CONFIGURED'.) | ||
if (e.name === 'UsageError') { | ||
return; | ||
@@ -102,3 +103,3 @@ } | ||
describe('with an `error` callback provided', function () { | ||
it('should trigger the `error` callback', function (done){ | ||
it('should not hang forever, go into an infinite loop, or crash the process -- instead, throw a predictable UsageError', function (done){ | ||
var m = Machine.build(NM_DEF_FIXTURE); | ||
@@ -112,2 +113,47 @@ | ||
error: function (err) { | ||
return done(new Error('Should never have made it here')); | ||
}, | ||
success: function (){ | ||
return done(new Error('Should never have made it here')); | ||
} | ||
}); | ||
} catch (e) { | ||
if (e.name === 'UsageError') { return done(); } | ||
return done(e); | ||
} | ||
return done(new Error('Should have thrown a UsageError')); | ||
}); | ||
});//</describe :: with an `error` callback provided> | ||
describe('WITHOUT providing an `error` callback', function () { | ||
it('should not hang forever, go into an infinite loop, or crash the process -- instead, throw a predictable UsageError', function (done){ | ||
var m = Machine.build(NM_DEF_FIXTURE); | ||
try { | ||
m({ foo: 'bar' }).exec({ | ||
success: function (){ | ||
return done(new Error('Should never have called this callback!')); | ||
} | ||
}); | ||
} catch (e) { | ||
if (e.name === 'UsageError') { return done(); } | ||
return done(e); | ||
} | ||
return done(new Error('Should have thrown a UsageError')); | ||
}); | ||
});//</describe :: WITHOUT providing an `error` callback> | ||
});//</describe :: calling .exec(perExitCallbacks)> | ||
describe('calling .switch(perExitCallbacks)', function () { | ||
describe('with an `error` callback provided', function () { | ||
it('should trigger the `error` callback', function (done){ | ||
var m = Machine.build(NM_DEF_FIXTURE); | ||
// Save a reference to the original machine instance for comparison below. | ||
var _origMachineInstance = m({ foo: 'bar' }); | ||
try { | ||
_origMachineInstance.switch({ | ||
error: function (err) { | ||
if (err) { | ||
@@ -135,3 +181,3 @@ // if (err.exit !== 'error') { return done(new Error('The error should have had a `exit` property set to `error`. Here\'s the whole stack:\n '+err.stack)); } | ||
try { | ||
m({ foo: 'bar' }).exec({ | ||
m({ foo: 'bar' }).switch({ | ||
success: function (){ | ||
@@ -142,3 +188,4 @@ return done(new Error('Should never have called this callback!')); | ||
} catch (e) { | ||
if (e.code === 'E_NO_ERROR_CALLBACK_CONFIGURED') { | ||
// (Note: In past versions, this was indicated by a code of 'E_NO_ERROR_CALLBACK_CONFIGURED'.) | ||
if (e.name === 'UsageError') { | ||
return done(); | ||
@@ -152,3 +199,3 @@ } | ||
});//</describe :: calling .exec(perExitCallbacks)> | ||
});//</describe :: calling .switch(perExitCallbacks)> | ||
@@ -208,3 +255,4 @@ | ||
} catch (e) { | ||
if (e.code === 'E_NO_ERROR_CALLBACK_CONFIGURED') { | ||
// (Note: In past versions, this was indicated by a code of 'E_NO_ERROR_CALLBACK_CONFIGURED'.) | ||
if (e.name === 'UsageError') { | ||
return; | ||
@@ -282,3 +330,4 @@ } | ||
} catch (e) { | ||
if (e.code === 'E_NO_ERROR_CALLBACK_CONFIGURED') { | ||
// (Note: In past versions, this was indicated by a code of 'E_NO_ERROR_CALLBACK_CONFIGURED'.) | ||
if (e.name === 'UsageError') { | ||
return done(); | ||
@@ -342,3 +391,4 @@ } | ||
} catch (e) { | ||
if (e.code === 'E_NO_ERROR_CALLBACK_CONFIGURED') { | ||
// (Note: In past versions, this was indicated by a code of 'E_NO_ERROR_CALLBACK_CONFIGURED'.) | ||
if (e.name === 'UsageError') { | ||
return; | ||
@@ -416,3 +466,4 @@ } | ||
} catch (e) { | ||
if (e.code === 'E_NO_ERROR_CALLBACK_CONFIGURED') { | ||
// (Note: In past versions, this was indicated by a code of 'E_NO_ERROR_CALLBACK_CONFIGURED'.) | ||
if (e.name === 'UsageError') { | ||
return done(); | ||
@@ -419,0 +470,0 @@ } |
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
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
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
330069
41
6878
4
+ Addedrttc@10.0.1(transitive)
- Removedlodash@3.10.1(transitive)
- Removedrttc@9.8.2(transitive)
Updatedrttc@^10.0.0-1