@gasket/core
Advanced tools
Comparing version 7.0.0-next.54 to 7.0.0-next.55
@@ -5,9 +5,16 @@ "use strict"; | ||
}); | ||
Object.defineProperty(exports, "default", { | ||
enumerable: true, | ||
get: function() { | ||
return _default; | ||
function _export(target, all) { | ||
for(var name in all)Object.defineProperty(target, name, { | ||
enumerable: true, | ||
get: all[name] | ||
}); | ||
} | ||
_export(exports, { | ||
GasketEngine: function() { | ||
return GasketEngine; | ||
}, | ||
lifecycleMethods: function() { | ||
return lifecycleMethods; | ||
} | ||
}); | ||
const _debug = /*#__PURE__*/ _interop_require_default(require("debug")); | ||
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { | ||
@@ -42,15 +49,15 @@ try { | ||
} | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
default: obj | ||
}; | ||
} | ||
const debug = (0, _debug.default)('gasket:engine'); | ||
let dynamicNamingId = 0; | ||
const lifecycleMethods = [ | ||
'exec', | ||
'execSync', | ||
'execWaterfall', | ||
'execWaterfallSync', | ||
'execMap', | ||
'execMapSync', | ||
'execApply', | ||
'execApplySync' | ||
]; | ||
class GasketEngine { | ||
/** | ||
* Resolves plugins | ||
* @param plugins | ||
* @private | ||
*/ _registerPlugins(plugins) { | ||
_registerPlugins(plugins) { | ||
// map the plugin name to module contents for easy lookup | ||
@@ -110,2 +117,20 @@ this._pluginMap = plugins.reduce((acc, plugin)=>{ | ||
} | ||
_registerActions() { | ||
this.actions = {}; | ||
const actionPluginMap = {}; | ||
Object.entries(this._pluginMap).forEach(([pluginName, plugin])=>{ | ||
const { actions } = plugin; | ||
if (actions) { | ||
Object.keys(actions).forEach((actionName)=>{ | ||
if (actionPluginMap[actionName]) { | ||
// eslint-disable-next-line no-console | ||
console.error(`Action '${actionName}' from '${pluginName}' was registered by '${actionPluginMap[actionName]}'`); | ||
return; | ||
} | ||
actionPluginMap[actionName] = plugin.name; | ||
this.actions[actionName] = actions[actionName]; | ||
}); | ||
} | ||
}); | ||
} | ||
/** | ||
@@ -137,3 +162,5 @@ * Injects additional lifecycle hooks at runtime. | ||
}, | ||
callback: handler.bind(null, this) | ||
invoke: (gasket, ...args)=>{ | ||
return handler(gasket, ...args); | ||
} | ||
}; | ||
@@ -146,2 +173,3 @@ delete this._plans[event]; | ||
* plugins to finish. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -151,7 +179,7 @@ * @param {...*} args Args for hooks | ||
* the order executed | ||
*/ exec(event, ...args) { | ||
*/ exec(gasket, event, ...args) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'exec', | ||
prepare: (hookConfig, trace)=>{ | ||
prepare: (hookConfig)=>{ | ||
const subscribers = hookConfig.subscribers; | ||
@@ -161,6 +189,7 @@ const executionPlan = []; | ||
this._executeInOrder(hookConfig, (plugin)=>{ | ||
pluginThunks[plugin] = (pluginTasks, ...passedArgs)=>{ | ||
pluginThunks[plugin] = (passedGasket, pluginTasks, ...passedArgs)=>{ | ||
pluginTasks[plugin] = Promise.all(subscribers[plugin].ordering.after.map((dep)=>pluginTasks[dep])).then(()=>{ | ||
trace(plugin); | ||
return subscribers[plugin].callback(...passedArgs); | ||
var _passedGasket_traceHookStart; | ||
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event); | ||
return subscribers[plugin].invoke(passedGasket, ...passedArgs); | ||
}); | ||
@@ -175,3 +204,3 @@ return pluginTasks[plugin]; | ||
const pluginTasks = {}; | ||
return Promise.all(executionPlan.map((fn)=>fn(pluginTasks, ...args))); | ||
return Promise.all(executionPlan.map((fn)=>fn(gasket, pluginTasks, ...args))); | ||
} | ||
@@ -185,2 +214,3 @@ }); | ||
* possible. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -190,13 +220,14 @@ * @param {...*} args Args for hooks | ||
* the order executed | ||
*/ execSync(event, ...args) { | ||
*/ execSync(gasket, event, ...args) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execSync', | ||
prepare: (hookConfig, trace)=>{ | ||
prepare: (hookConfig)=>{ | ||
const subscribers = hookConfig.subscribers; | ||
const executionPlan = []; | ||
this._executeInOrder(hookConfig, (plugin)=>{ | ||
executionPlan.push((...execArgs)=>{ | ||
trace(plugin); | ||
return subscribers[plugin].callback(...execArgs); | ||
executionPlan.push((passedGasket, ...execArgs)=>{ | ||
var _passedGasket_traceHookStart; | ||
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event); | ||
return subscribers[plugin].invoke(passedGasket, ...execArgs); | ||
}); | ||
@@ -207,3 +238,3 @@ }); | ||
exec: (executionPlan)=>{ | ||
return executionPlan.map((fn)=>fn(...args)); | ||
return executionPlan.map((fn)=>fn(gasket, ...args)); | ||
} | ||
@@ -217,2 +248,3 @@ }); | ||
* present in the map. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -222,14 +254,15 @@ * @param {...*} args Args for hooks | ||
* the plugin and each value the result from the hook | ||
*/ execMap(event, ...args) { | ||
*/ execMap(gasket, event, ...args) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execMap', | ||
prepare: (hookConfig, trace)=>{ | ||
prepare: (hookConfig)=>{ | ||
const subscribers = hookConfig.subscribers; | ||
const executionPlan = {}; | ||
this._executeInOrder(hookConfig, (plugin)=>{ | ||
executionPlan[plugin] = (pluginTasks, ...passedArgs)=>{ | ||
executionPlan[plugin] = (passedGasket, pluginTasks, ...passedArgs)=>{ | ||
pluginTasks[plugin] = Promise.all(subscribers[plugin].ordering.after.map((dep)=>pluginTasks[dep])).then(()=>{ | ||
trace(plugin); | ||
return subscribers[plugin].callback(...passedArgs); | ||
var _passedGasket_traceHookStart; | ||
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event); | ||
return subscribers[plugin].invoke(passedGasket, ...passedArgs); | ||
}); | ||
@@ -247,3 +280,3 @@ return pluginTasks[plugin]; | ||
var _ref = _async_to_generator(function*([plugin, thunk]) { | ||
resultMap[plugin] = yield thunk(pluginTasks, ...args); | ||
resultMap[plugin] = yield thunk(gasket, pluginTasks, ...args); | ||
}); | ||
@@ -261,2 +294,3 @@ return function(_) { | ||
* Like `execMap`, only all hooks must execute synchronously | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -266,13 +300,14 @@ * @param {...*} args Args for hooks | ||
* the plugin and each value the result from the hook | ||
*/ execMapSync(event, ...args) { | ||
*/ execMapSync(gasket, event, ...args) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execMapSync', | ||
prepare: (hookConfig, trace)=>{ | ||
prepare: (hookConfig)=>{ | ||
const subscribers = hookConfig.subscribers; | ||
const executionPlan = []; | ||
this._executeInOrder(hookConfig, (plugin)=>{ | ||
executionPlan.push((resultMap, ...passedArgs)=>{ | ||
trace(plugin); | ||
resultMap[plugin] = subscribers[plugin].callback(...passedArgs); | ||
executionPlan.push((passedGasket, resultMap, ...passedArgs)=>{ | ||
var _passedGasket_traceHookStart; | ||
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event); | ||
resultMap[plugin] = subscribers[plugin].invoke(passedGasket, ...passedArgs); | ||
}); | ||
@@ -284,3 +319,3 @@ }); | ||
const resultMap = {}; | ||
executionPlan.forEach((thunk)=>thunk(resultMap, ...args)); | ||
executionPlan.forEach((thunk)=>thunk(gasket, resultMap, ...args)); | ||
return resultMap; | ||
@@ -294,2 +329,3 @@ } | ||
* to the next hook. It's like an asynchronous version of `Array.prototype.reduce`. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -299,14 +335,16 @@ * @param {any} value Value to pass to initial hook | ||
* @returns {Promise} The result of the final executed hook. | ||
*/ execWaterfall(event, value, ...otherArgs) { | ||
*/ execWaterfall(gasket, event, value, ...otherArgs) { | ||
const type = 'execWaterfall'; | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execWaterfall', | ||
prepare: (hookConfig, trace)=>{ | ||
type, | ||
prepare: (hookConfig)=>{ | ||
const subscribers = hookConfig.subscribers; | ||
return (passedValue, ...args)=>{ | ||
return (passedGasket, passedValue, ...args)=>{ | ||
let result = Promise.resolve(passedValue); | ||
this._executeInOrder(hookConfig, (plugin)=>{ | ||
result = result.then((nextValue)=>{ | ||
trace(plugin); | ||
return subscribers[plugin].callback(nextValue, ...args); | ||
var _passedGasket_traceHookStart; | ||
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event); | ||
return subscribers[plugin].invoke(passedGasket, nextValue, ...args); | ||
}); | ||
@@ -318,3 +356,3 @@ }); | ||
exec: (executionPlan)=>{ | ||
return executionPlan(value, ...otherArgs); | ||
return executionPlan(gasket, value, ...otherArgs); | ||
} | ||
@@ -328,2 +366,3 @@ }); | ||
* methods whenever possible. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -333,13 +372,14 @@ * @param {any} value Value to pass to initial hook | ||
* @returns {Promise} The result of the final executed hook. | ||
*/ execWaterfallSync(event, value, ...otherArgs) { | ||
*/ execWaterfallSync(gasket, event, value, ...otherArgs) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execWaterfallSync', | ||
prepare: (hookConfig, trace)=>{ | ||
prepare: (hookConfig)=>{ | ||
const subscribers = hookConfig.subscribers; | ||
return (passedValue, ...args)=>{ | ||
return (passedGasket, passedValue, ...args)=>{ | ||
let result = passedValue; | ||
this._executeInOrder(hookConfig, (plugin)=>{ | ||
trace(plugin); | ||
result = subscribers[plugin].callback(result, ...args); | ||
var _passedGasket_traceHookStart; | ||
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event); | ||
result = subscribers[plugin].invoke(passedGasket, result, ...args); | ||
}); | ||
@@ -350,3 +390,3 @@ return result; | ||
exec: (executionPlan)=>{ | ||
return executionPlan(value, ...otherArgs); | ||
return executionPlan(gasket, value, ...otherArgs); | ||
} | ||
@@ -359,2 +399,3 @@ }); | ||
* the plugin itself. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -364,7 +405,7 @@ * @param {Function} applyFn Function to apply | ||
* the order executed | ||
*/ execApply(event, applyFn) { | ||
*/ execApply(gasket, event, applyFn) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execApply', | ||
prepare: (hookConfig, trace)=>{ | ||
prepare: (hookConfig)=>{ | ||
const subscribers = hookConfig.subscribers; | ||
@@ -374,6 +415,8 @@ const executionPlan = []; | ||
this._executeInOrder(hookConfig, (plugin)=>{ | ||
pluginThunks[plugin] = (fn, pluginTasks)=>{ | ||
pluginThunks[plugin] = (passedGasket, passedApplyFn, pluginTasks)=>{ | ||
const callback = (...args)=>subscribers[plugin].invoke(passedGasket, ...args); | ||
pluginTasks[plugin] = Promise.all(subscribers[plugin].ordering.after.map((dep)=>pluginTasks[dep])).then(()=>{ | ||
trace(plugin); | ||
return fn(this._pluginMap[plugin], subscribers[plugin].callback); | ||
var _passedGasket_traceHookStart; | ||
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event); | ||
return passedApplyFn(this._pluginMap[plugin], callback); | ||
}); | ||
@@ -388,3 +431,3 @@ return pluginTasks[plugin]; | ||
const pluginTasks = {}; | ||
return Promise.all(executionPlan.map((fn)=>fn(applyFn, pluginTasks))); | ||
return Promise.all(executionPlan.map((fn)=>fn(gasket, applyFn, pluginTasks))); | ||
} | ||
@@ -395,2 +438,3 @@ }); | ||
* Like `execApply`, only all hooks must execute synchronously. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -400,13 +444,15 @@ * @param {Function} applyFn Function to apply | ||
* the order executed | ||
*/ execApplySync(event, applyFn) { | ||
*/ execApplySync(gasket, event, applyFn) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execApplySync', | ||
prepare: (hookConfig, trace)=>{ | ||
prepare: (hookConfig)=>{ | ||
const subscribers = hookConfig.subscribers; | ||
const executionPlan = []; | ||
this._executeInOrder(hookConfig, (plugin)=>{ | ||
executionPlan.push((fn)=>{ | ||
trace(plugin); | ||
return fn(this._pluginMap[plugin], subscribers[plugin].callback); | ||
executionPlan.push((passedGasket, passApplyFn)=>{ | ||
var _passedGasket_traceHookStart; | ||
const callback = (...args)=>subscribers[plugin].invoke(passedGasket, ...args); | ||
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event); | ||
return passApplyFn(this._pluginMap[plugin], callback); | ||
}); | ||
@@ -417,3 +463,3 @@ }); | ||
exec: (executionPlan)=>{ | ||
return executionPlan.map((fn)=>fn(applyFn)); | ||
return executionPlan.map((fn)=>fn(gasket, applyFn)); | ||
} | ||
@@ -426,2 +472,3 @@ }); | ||
* @param {object} options options | ||
* @param [options.gasket] | ||
* @param options.event | ||
@@ -433,14 +480,6 @@ * @param options.type | ||
*/ _execWithCachedPlan({ event, type, prepare, exec }) { | ||
debug(`${' '.repeat(this._traceDepth++)}${type} ${event}`); | ||
const traceDepth = this._traceDepth; | ||
const trace = (plugin)=>debug(`${' '.repeat(traceDepth)}${plugin}:${event}`); | ||
const hookConfig = this._getHookConfig(event); | ||
const plansByType = this._plans[event] || (this._plans[event] = {}); | ||
const plan = plansByType[type] || (plansByType[type] = prepare(hookConfig, trace)); | ||
const result = exec(plan); | ||
if (typeof (result === null || result === void 0 ? void 0 : result.finally) === 'function') { | ||
return result.finally(()=>this._traceDepth--); | ||
} | ||
this._traceDepth--; | ||
return result; | ||
const plan = plansByType[type] || (plansByType[type] = prepare(hookConfig)); | ||
return exec(plan); | ||
} | ||
@@ -533,16 +572,7 @@ /** | ||
this._plans = {}; | ||
this._traceDepth = 0; | ||
this._registerPlugins(plugins); | ||
this._registerHooks(); | ||
this._registerActions(); | ||
// Allow methods to be called without context (to support destructuring) | ||
[ | ||
'exec', | ||
'execWaterfall', | ||
'execMap', | ||
'execApply', | ||
'execSync', | ||
'execWaterfallSync', | ||
'execMapSync', | ||
'execApplySync' | ||
].forEach((method)=>{ | ||
lifecycleMethods.forEach((method)=>{ | ||
this[method] = this[method].bind(this); | ||
@@ -552,2 +582,1 @@ }); | ||
} | ||
const _default = GasketEngine; |
114
cjs/index.js
@@ -1,2 +0,2 @@ | ||
/* eslint-disable no-console, no-process-env */ "use strict"; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
@@ -12,113 +12,9 @@ value: true | ||
_export(exports, { | ||
GasketEngine: function() { | ||
return _engine.default; | ||
Gasket: function() { | ||
return _gasket.Gasket; | ||
}, | ||
makeGasket: function() { | ||
return makeGasket; | ||
return _gasket.makeGasket; | ||
} | ||
}); | ||
const _engine = /*#__PURE__*/ _interop_require_default(require("./engine.js")); | ||
const _utils = require("@gasket/utils"); | ||
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { | ||
try { | ||
var info = gen[key](arg); | ||
var value = info.value; | ||
} catch (error) { | ||
reject(error); | ||
return; | ||
} | ||
if (info.done) { | ||
resolve(value); | ||
} else { | ||
Promise.resolve(value).then(_next, _throw); | ||
} | ||
} | ||
function _async_to_generator(fn) { | ||
return function() { | ||
var self = this, args = arguments; | ||
return new Promise(function(resolve, reject) { | ||
var gen = fn.apply(self, args); | ||
function _next(value) { | ||
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); | ||
} | ||
function _throw(err) { | ||
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); | ||
} | ||
_next(undefined); | ||
}); | ||
}; | ||
} | ||
function _interop_require_default(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
default: obj | ||
}; | ||
} | ||
/** | ||
* Get the environment to use for the gasket instance. | ||
* Defaults to `local`. | ||
* @returns {string} env | ||
*/ function getEnvironment() { | ||
const { GASKET_ENV } = process.env; | ||
if (GASKET_ENV) { | ||
return GASKET_ENV; | ||
} | ||
console.warn(`No GASKET_ENV env variable set; defaulting to "local".`); | ||
return 'local'; | ||
} | ||
/* eslint-enable no-console, no-process-env */ // TODO: Add JSDoc types | ||
/** | ||
* | ||
* @param instance | ||
*/ function registerActions(instance) { | ||
const actions = {}; | ||
const actionPluginMap = {}; | ||
instance.execApplySync('actions', function() { | ||
var _ref = _async_to_generator(function*(plugin, handler) { | ||
const results = handler(); // The gasket parameter is automatically applied | ||
if (results) { | ||
Object.keys(results).forEach((actionName)=>{ | ||
if (actionPluginMap[actionName]) { | ||
// eslint-disable-next-line no-console | ||
console.error(`Action '${actionName}' from '${plugin.name}' was registered by '${actionPluginMap[actionName]}'`); | ||
return; | ||
} | ||
actionPluginMap[actionName] = plugin.name; | ||
actions[actionName] = results[actionName]; | ||
}); | ||
} | ||
}); | ||
return function(plugin, handler) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
}()); | ||
return actions; | ||
} | ||
// TODO: Add JSDoc types | ||
class Gasket extends _engine.default { | ||
constructor(gasketConfig){ | ||
var _config; | ||
const env = getEnvironment(); | ||
const config = (0, _utils.applyConfigOverrides)(gasketConfig, { | ||
env | ||
}); | ||
config.env = env; | ||
var _root; | ||
(_root = (_config = config).root) !== null && _root !== void 0 ? _root : _config.root = process.cwd(); | ||
// prune nullish and/or empty plugins | ||
config.plugins = config.plugins.filter(Boolean).filter((plugin)=>Boolean(plugin.name) || Boolean(plugin.hooks)); | ||
// start the engine | ||
super(config.plugins); | ||
this.config = config; | ||
this.command = null; | ||
this.execSync('init'); | ||
this.actions = registerActions(this); | ||
this.config = this.execWaterfallSync('configure', config); | ||
} | ||
} | ||
// TODO: Add JSDoc types | ||
/** | ||
* | ||
* @param gasketConfigDefinition | ||
*/ function makeGasket(gasketConfigDefinition) { | ||
return new Gasket(gasketConfigDefinition); | ||
} | ||
const _gasket = require("./gasket.js"); |
@@ -1,8 +0,11 @@ | ||
import debugPkg from 'debug'; | ||
let dynamicNamingId = 0; | ||
const debug = debugPkg('gasket:engine'); | ||
export const lifecycleMethods = [ | ||
'exec', 'execSync', | ||
'execWaterfall', 'execWaterfallSync', | ||
'execMap', 'execMapSync', | ||
'execApply', 'execApplySync' | ||
]; | ||
let dynamicNamingId = 0; | ||
class GasketEngine { | ||
export class GasketEngine { | ||
constructor(plugins) { | ||
@@ -15,19 +18,13 @@ if (!plugins || !Array.isArray(plugins) || !plugins.length) { | ||
this._plans = {}; | ||
this._traceDepth = 0; | ||
this._registerPlugins(plugins); | ||
this._registerHooks(); | ||
this._registerActions(); | ||
// Allow methods to be called without context (to support destructuring) | ||
[ | ||
'exec', 'execWaterfall', 'execMap', 'execApply', | ||
'execSync', 'execWaterfallSync', 'execMapSync', 'execApplySync' | ||
].forEach(method => { this[method] = this[method].bind(this); }); | ||
lifecycleMethods.forEach(method => { | ||
this[method] = this[method].bind(this); | ||
}); | ||
} | ||
/** | ||
* Resolves plugins | ||
* @param plugins | ||
* @private | ||
*/ | ||
_registerPlugins(plugins) { | ||
@@ -94,2 +91,24 @@ | ||
_registerActions() { | ||
this.actions = {}; | ||
const actionPluginMap = {}; | ||
Object.entries(this._pluginMap).forEach(([pluginName, plugin]) => { | ||
const { actions } = plugin; | ||
if (actions) { | ||
Object.keys(actions).forEach(actionName => { | ||
if (actionPluginMap[actionName]) { | ||
// eslint-disable-next-line no-console | ||
console.error( | ||
`Action '${actionName}' from '${pluginName}' was registered by '${actionPluginMap[actionName]}'` | ||
); | ||
return; | ||
} | ||
actionPluginMap[actionName] = plugin.name; | ||
this.actions[actionName] = actions[actionName]; | ||
}); | ||
} | ||
}); | ||
} | ||
/** | ||
@@ -123,3 +142,5 @@ * Injects additional lifecycle hooks at runtime. | ||
}, | ||
callback: handler.bind(null, this) | ||
invoke: (gasket, ...args) => { | ||
return handler(gasket, ...args); | ||
} | ||
}; | ||
@@ -134,2 +155,3 @@ | ||
* plugins to finish. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -140,7 +162,7 @@ * @param {...*} args Args for hooks | ||
*/ | ||
exec(event, ...args) { | ||
exec(gasket, event, ...args) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'exec', | ||
prepare: (hookConfig, trace) => { | ||
prepare: (hookConfig) => { | ||
const subscribers = hookConfig.subscribers; | ||
@@ -150,8 +172,8 @@ const executionPlan = []; | ||
this._executeInOrder(hookConfig, plugin => { | ||
pluginThunks[plugin] = (pluginTasks, ...passedArgs) => { | ||
pluginThunks[plugin] = (passedGasket, pluginTasks, ...passedArgs) => { | ||
pluginTasks[plugin] = Promise | ||
.all(subscribers[plugin].ordering.after.map(dep => pluginTasks[dep])) | ||
.then(() => { | ||
trace(plugin); | ||
return subscribers[plugin].callback(...passedArgs); | ||
passedGasket.traceHookStart?.(plugin, event); | ||
return subscribers[plugin].invoke(passedGasket, ...passedArgs); | ||
}); | ||
@@ -167,3 +189,3 @@ return pluginTasks[plugin]; | ||
const pluginTasks = {}; | ||
return Promise.all(executionPlan.map(fn => fn(pluginTasks, ...args))); | ||
return Promise.all(executionPlan.map(fn => fn(gasket, pluginTasks, ...args))); | ||
} | ||
@@ -178,2 +200,3 @@ }); | ||
* possible. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -184,13 +207,13 @@ * @param {...*} args Args for hooks | ||
*/ | ||
execSync(event, ...args) { | ||
execSync(gasket, event, ...args) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execSync', | ||
prepare: (hookConfig, trace) => { | ||
prepare: (hookConfig) => { | ||
const subscribers = hookConfig.subscribers; | ||
const executionPlan = []; | ||
this._executeInOrder(hookConfig, plugin => { | ||
executionPlan.push((...execArgs) => { | ||
trace(plugin); | ||
return subscribers[plugin].callback(...execArgs); | ||
executionPlan.push((passedGasket, ...execArgs) => { | ||
passedGasket.traceHookStart?.(plugin, event); | ||
return subscribers[plugin].invoke(passedGasket, ...execArgs); | ||
}); | ||
@@ -202,3 +225,3 @@ }); | ||
exec: executionPlan => { | ||
return executionPlan.map(fn => fn(...args)); | ||
return executionPlan.map(fn => fn(gasket, ...args)); | ||
} | ||
@@ -213,2 +236,3 @@ }); | ||
* present in the map. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -219,16 +243,16 @@ * @param {...*} args Args for hooks | ||
*/ | ||
execMap(event, ...args) { | ||
execMap(gasket, event, ...args) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execMap', | ||
prepare: (hookConfig, trace) => { | ||
prepare: (hookConfig) => { | ||
const subscribers = hookConfig.subscribers; | ||
const executionPlan = {}; | ||
this._executeInOrder(hookConfig, plugin => { | ||
executionPlan[plugin] = (pluginTasks, ...passedArgs) => { | ||
executionPlan[plugin] = (passedGasket, pluginTasks, ...passedArgs) => { | ||
pluginTasks[plugin] = Promise | ||
.all(subscribers[plugin].ordering.after.map(dep => pluginTasks[dep])) | ||
.then(() => { | ||
trace(plugin); | ||
return subscribers[plugin].callback(...passedArgs); | ||
passedGasket.traceHookStart?.(plugin, event); | ||
return subscribers[plugin].invoke(passedGasket, ...passedArgs); | ||
}); | ||
@@ -248,3 +272,3 @@ return pluginTasks[plugin]; | ||
.map(async ([plugin, thunk]) => { | ||
resultMap[plugin] = await thunk(pluginTasks, ...args); | ||
resultMap[plugin] = await thunk(gasket, pluginTasks, ...args); | ||
}) | ||
@@ -259,2 +283,3 @@ ); | ||
* Like `execMap`, only all hooks must execute synchronously | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -265,13 +290,13 @@ * @param {...*} args Args for hooks | ||
*/ | ||
execMapSync(event, ...args) { | ||
execMapSync(gasket, event, ...args) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execMapSync', | ||
prepare: (hookConfig, trace) => { | ||
prepare: (hookConfig) => { | ||
const subscribers = hookConfig.subscribers; | ||
const executionPlan = []; | ||
this._executeInOrder(hookConfig, plugin => { | ||
executionPlan.push((resultMap, ...passedArgs) => { | ||
trace(plugin); | ||
resultMap[plugin] = subscribers[plugin].callback(...passedArgs); | ||
executionPlan.push((passedGasket, resultMap, ...passedArgs) => { | ||
passedGasket.traceHookStart?.(plugin, event); | ||
resultMap[plugin] = subscribers[plugin].invoke(passedGasket, ...passedArgs); | ||
}); | ||
@@ -284,3 +309,3 @@ }); | ||
const resultMap = {}; | ||
executionPlan.forEach(thunk => thunk(resultMap, ...args)); | ||
executionPlan.forEach(thunk => thunk(gasket, resultMap, ...args)); | ||
return resultMap; | ||
@@ -295,2 +320,3 @@ } | ||
* to the next hook. It's like an asynchronous version of `Array.prototype.reduce`. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -301,10 +327,11 @@ * @param {any} value Value to pass to initial hook | ||
*/ | ||
execWaterfall(event, value, ...otherArgs) { | ||
execWaterfall(gasket, event, value, ...otherArgs) { | ||
const type = 'execWaterfall'; | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execWaterfall', | ||
prepare: (hookConfig, trace) => { | ||
type, | ||
prepare: (hookConfig) => { | ||
const subscribers = hookConfig.subscribers; | ||
return (passedValue, ...args) => { | ||
return (passedGasket, passedValue, ...args) => { | ||
let result = Promise.resolve(passedValue); | ||
@@ -314,4 +341,4 @@ | ||
result = result.then((nextValue) => { | ||
trace(plugin); | ||
return subscribers[plugin].callback(nextValue, ...args); | ||
passedGasket.traceHookStart?.(plugin, event); | ||
return subscribers[plugin].invoke(passedGasket, nextValue, ...args); | ||
}); | ||
@@ -323,4 +350,4 @@ }); | ||
}, | ||
exec: executionPlan => { | ||
return executionPlan(value, ...otherArgs); | ||
exec: (executionPlan) => { | ||
return executionPlan(gasket, value, ...otherArgs); | ||
} | ||
@@ -335,2 +362,3 @@ }); | ||
* methods whenever possible. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -341,15 +369,15 @@ * @param {any} value Value to pass to initial hook | ||
*/ | ||
execWaterfallSync(event, value, ...otherArgs) { | ||
execWaterfallSync(gasket, event, value, ...otherArgs) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execWaterfallSync', | ||
prepare: (hookConfig, trace) => { | ||
prepare: (hookConfig) => { | ||
const subscribers = hookConfig.subscribers; | ||
return (passedValue, ...args) => { | ||
return (passedGasket, passedValue, ...args) => { | ||
let result = passedValue; | ||
this._executeInOrder(hookConfig, plugin => { | ||
trace(plugin); | ||
result = subscribers[plugin].callback(result, ...args); | ||
passedGasket.traceHookStart?.(plugin, event); | ||
result = subscribers[plugin].invoke(passedGasket, result, ...args); | ||
}); | ||
@@ -361,3 +389,3 @@ | ||
exec: executionPlan => { | ||
return executionPlan(value, ...otherArgs); | ||
return executionPlan(gasket, value, ...otherArgs); | ||
} | ||
@@ -371,2 +399,3 @@ }); | ||
* the plugin itself. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -377,7 +406,7 @@ * @param {Function} applyFn Function to apply | ||
*/ | ||
execApply(event, applyFn) { | ||
execApply(gasket, event, applyFn) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execApply', | ||
prepare: (hookConfig, trace) => { | ||
prepare: (hookConfig) => { | ||
const subscribers = hookConfig.subscribers; | ||
@@ -387,8 +416,9 @@ const executionPlan = []; | ||
this._executeInOrder(hookConfig, plugin => { | ||
pluginThunks[plugin] = (fn, pluginTasks) => { | ||
pluginThunks[plugin] = (passedGasket, passedApplyFn, pluginTasks) => { | ||
const callback = (...args) => subscribers[plugin].invoke(passedGasket, ...args); | ||
pluginTasks[plugin] = Promise | ||
.all(subscribers[plugin].ordering.after.map(dep => pluginTasks[dep])) | ||
.then(() => { | ||
trace(plugin); | ||
return fn(this._pluginMap[plugin], subscribers[plugin].callback); | ||
passedGasket.traceHookStart?.(plugin, event); | ||
return passedApplyFn(this._pluginMap[plugin], callback); | ||
}); | ||
@@ -404,3 +434,3 @@ return pluginTasks[plugin]; | ||
const pluginTasks = {}; | ||
return Promise.all(executionPlan.map(fn => fn(applyFn, pluginTasks))); | ||
return Promise.all(executionPlan.map(fn => fn(gasket, applyFn, pluginTasks))); | ||
} | ||
@@ -412,2 +442,3 @@ }); | ||
* Like `execApply`, only all hooks must execute synchronously. | ||
* @param gasket | ||
* @param {string} event The event to execute | ||
@@ -418,13 +449,14 @@ * @param {Function} applyFn Function to apply | ||
*/ | ||
execApplySync(event, applyFn) { | ||
execApplySync(gasket, event, applyFn) { | ||
return this._execWithCachedPlan({ | ||
event, | ||
type: 'execApplySync', | ||
prepare: (hookConfig, trace) => { | ||
prepare: (hookConfig) => { | ||
const subscribers = hookConfig.subscribers; | ||
const executionPlan = []; | ||
this._executeInOrder(hookConfig, plugin => { | ||
executionPlan.push(fn => { | ||
trace(plugin); | ||
return fn(this._pluginMap[plugin], subscribers[plugin].callback); | ||
this._executeInOrder(hookConfig, (plugin) => { | ||
executionPlan.push((passedGasket, passApplyFn) => { | ||
const callback = (...args) => subscribers[plugin].invoke(passedGasket, ...args); | ||
passedGasket.traceHookStart?.(plugin, event); | ||
return passApplyFn(this._pluginMap[plugin], callback); | ||
}); | ||
@@ -435,3 +467,3 @@ }); | ||
exec: executionPlan => { | ||
return executionPlan.map(fn => fn(applyFn)); | ||
return executionPlan.map(fn => fn(gasket, applyFn)); | ||
} | ||
@@ -445,2 +477,3 @@ }); | ||
* @param {object} options options | ||
* @param [options.gasket] | ||
* @param options.event | ||
@@ -453,6 +486,2 @@ * @param options.type | ||
_execWithCachedPlan({ event, type, prepare, exec }) { | ||
debug(`${' '.repeat(this._traceDepth++)}${type} ${event}`); | ||
const traceDepth = this._traceDepth; | ||
const trace = plugin => debug(`${' '.repeat(traceDepth)}${plugin}:${event}`); | ||
const hookConfig = this._getHookConfig(event); | ||
@@ -463,11 +492,6 @@ const plansByType = this._plans[event] || ( | ||
const plan = plansByType[type] || ( | ||
plansByType[type] = prepare(hookConfig, trace) | ||
plansByType[type] = prepare(hookConfig) | ||
); | ||
const result = exec(plan); | ||
if (typeof result?.finally === 'function') { | ||
return result.finally(() => this._traceDepth--); | ||
} | ||
this._traceDepth--; | ||
return result; | ||
return exec(plan); | ||
} | ||
@@ -567,3 +591,1 @@ | ||
} | ||
export default GasketEngine; |
@@ -8,2 +8,10 @@ declare module '@gasket/core' { | ||
export type ActionId = keyof GasketActions; | ||
export type ActionHandler<Id extends ActionId> = ( | ||
gasket: Gasket, | ||
...args: Parameters<GasketActions[Id]> | ||
) => ReturnType<GasketActions[Id]>; | ||
// To be extended by plugins | ||
@@ -13,4 +21,4 @@ export interface HookExecTypes { | ||
init(): void | ||
actions(): Partial<GasketActions> | ||
configure(config: GasketConfig): GasketConfig | ||
ready(): MaybeAsync<void> | ||
} | ||
@@ -51,2 +59,5 @@ | ||
}; | ||
actions?: { | ||
[K in ActionId]?: ActionHandler<K>; | ||
}; | ||
}; | ||
@@ -66,2 +77,4 @@ | ||
actions: GasketActions | ||
exec<Id extends HookId>( | ||
@@ -104,2 +117,4 @@ hook: Id, | ||
export interface Gasket extends GasketEngine { | ||
constructor(config: GasketConfigDefinition); | ||
command: { | ||
@@ -110,5 +125,7 @@ id: string; | ||
new (config: GasketConfigDefinition): Gasket | ||
actions: GasketActions | ||
branch(): GasketBranch | ||
} | ||
export interface GasketBranch extends Gasket {} | ||
type PartialRecursive<T> = T extends Object | ||
@@ -115,0 +132,0 @@ ? { [K in keyof T]?: PartialRecursive<T[K]> } | undefined |
@@ -1,87 +0,6 @@ | ||
/* eslint-disable no-console, no-process-env */ | ||
import { Gasket, makeGasket } from './gasket.js'; | ||
import GasketEngine from './engine.js'; | ||
import { applyConfigOverrides } from '@gasket/utils'; | ||
/** | ||
* Get the environment to use for the gasket instance. | ||
* Defaults to `local`. | ||
* @returns {string} env | ||
*/ | ||
function getEnvironment() { | ||
const { GASKET_ENV } = process.env; | ||
if (GASKET_ENV) { | ||
return GASKET_ENV; | ||
} | ||
console.warn(`No GASKET_ENV env variable set; defaulting to "local".`); | ||
return 'local'; | ||
} | ||
/* eslint-enable no-console, no-process-env */ | ||
// TODO: Add JSDoc types | ||
/** | ||
* | ||
* @param instance | ||
*/ | ||
function registerActions(instance) { | ||
const actions = {}; | ||
const actionPluginMap = {}; | ||
instance.execApplySync('actions', async (plugin, handler) => { | ||
const results = handler(); // The gasket parameter is automatically applied | ||
if (results) { | ||
Object.keys(results).forEach(actionName => { | ||
if (actionPluginMap[actionName]) { | ||
// eslint-disable-next-line no-console | ||
console.error( | ||
`Action '${actionName}' from '${plugin.name}' was registered by '${actionPluginMap[actionName]}'` | ||
); | ||
return; | ||
} | ||
actionPluginMap[actionName] = plugin.name; | ||
actions[actionName] = results[actionName]; | ||
}); | ||
} | ||
}); | ||
return actions; | ||
} | ||
// TODO: Add JSDoc types | ||
class Gasket extends GasketEngine { | ||
constructor(gasketConfig) { | ||
const env = getEnvironment(); | ||
const config = applyConfigOverrides(gasketConfig, { env }); | ||
config.env = env; | ||
config.root ??= process.cwd(); | ||
// prune nullish and/or empty plugins | ||
config.plugins = config.plugins | ||
.filter(Boolean) | ||
.filter(plugin => Boolean(plugin.name) || Boolean(plugin.hooks)); | ||
// start the engine | ||
super(config.plugins); | ||
this.config = config; | ||
this.command = null; | ||
this.execSync('init'); | ||
this.actions = registerActions(this); | ||
this.config = this.execWaterfallSync('configure', config); | ||
} | ||
} | ||
// TODO: Add JSDoc types | ||
/** | ||
* | ||
* @param gasketConfigDefinition | ||
*/ | ||
function makeGasket(gasketConfigDefinition) { | ||
return new Gasket(gasketConfigDefinition); | ||
} | ||
export { | ||
makeGasket, | ||
GasketEngine | ||
Gasket, | ||
makeGasket | ||
}; |
{ | ||
"name": "@gasket/core", | ||
"version": "7.0.0-next.54", | ||
"version": "7.0.0-next.55", | ||
"description": "Entry point to setting up Gasket instances", | ||
@@ -91,3 +91,3 @@ "type": "module", | ||
}, | ||
"gitHead": "d2348e6988730b1a27097d587f75c629552799cb" | ||
"gitHead": "84a2654cf25651972e1bfbb0a54cb9f330ecb3ad" | ||
} |
65247
12
1595