You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Allow tasks to define which specific events they emit, and then perform the emitting within the main task.
Allow this task or other tasks to have special subtasks listening for such events, and when there is a match, the subtask is executed. The subtask is similar to a regular task except that:
It probably should not be allowed to define its own subtasks
It can return a value which can be collected by the executing task.
The emitting task will begin execution but upon encountering a call to execute hooks, will wait for all identified subtasks to execute (including their prompts), and then can use their return values to determine an order for applying the results.
Motivation
Sometimes tasks interact in ways where it is desirable that a single task allows consumers and can be provided by its consumers with information that it can use to determine how to present.
Alternatives considered
This is similar in some regards to the notion of hooks in #52, but:
It is intended more for tasks to define events rather than mrm-core to do so.
It attempts to allow subtasks whose results are collected and submitted to the hook registrant, allowing the registrant to apply the hooks in the manner/order deemed fit, potentially using the subtask return results to determine a suitable order or presentation.
So, as opposed to my understanding of #52, this particular notion of hooks (or events) in this issue is not for a hook that is a convenient way to override an existing core behavior on a single per-task basis.
This approach could conceivably be applied to mrm-core to override core code behavior, allowing core itself to register events which tasks could use. However, since in this proposal we are collecting results from multiple tasks before applying, core events would likely not be suitable since different tasks would not necessarily want overrides applied (e.g., one task might want to transform JSON and another would not). It would I think be a better separation in most cases for a single task to manage responsibility. This would also offer the advantage that projects do not need to wait for changes to core to make extensible, interacting behaviors.
Sample use cases
Allowing users of the readme task to present a single reusable template in config which, while referencing all potential variables for where other tasks' badges might be inserted (e.g., for linting, testing, coverage, license info, etc.), can also be used regardless of the tasks currently in use.
And they won't need to create the README in this manner first; the template would be able to create it in this sequence from the beginning.
When specifying extensions for use by ESLint, one might prefer the extensions be assembled in a particular order:
eslint --ext=js,ts,md,html
rather than
eslint --ext=html,js,md,ts
Tasks like a Markdown or README task, could offer "md" as an extension, a TypeScript task could offer "ts", etc., and then the eslint task could provide a template or otherwise assemble the extensions in a task-specifiable order.
And as with the previous example, there is no need for the user to edit the package.json ahead of time to specify the desired order; their task template could specify this ahead of time and be reused across project.
Proposed API
// Main task signaturemodule.exports=(userConfig,argv,executeHooks)=>{// This will invoke the hook with user config, argv, and hookConfig// Note that `returnResults` is an array, e.g., of stringsconstreturnResults=executeHooks('readme:add',hookConfig);// Use results...};module.exports=['readme:add'];// A task can both register hooks and add its own, as well as listen to its own eventsmainTask.listens={/* ... */};// See below// In another task// Accept hook config object separate from user config (and argv) so that executor can pass its ownconstreadmeAddSubtask=(userConfig,argv,hookConfig)=>{};// Indicate the used hooksmodule.exports=task;task.listens={'readme:add': readmeAddSubtask};
Sketch of control flow
(Steps are in series.)
Define a map allCollectedOptions
For each task task:
For each of a task's emitsevents, perform these steps:
Let the individual emits event be called event
For each of all other tasks besides task:
Let the individual task being iterated be called checkTask
Throw if checkTask is found to register itself for defining an event of the same name as event.
Begin executing the main module for task
Define an empty map executedEventsToOptions.
If, during execution, task calls executeHooks, then pause execution and follow these steps:
Let hookEvent be the name of the event with which executeHooks is invoked
Let hookConfig be any additional config passed (as the second argument of executeHooks).
Define an empty array results.
For each of all tasks (including task):
Let the individual task being iterated be called checkTask
If listens on checkTask is found with a hook subtask that matches hookEvent:
Let the individual matching subtask be called subtask
Look up hookEvent on the executedEventsToOptions map.
If a value is present in the map, assign it to collectedOptions
Otherwise:
Create an empty map collectedOptions.
For each option option of subtask:
If the CLI is configured to run in interactive mode and option is not present in allCollectedOptions, obtain option interactively as value.
Otherwise, obtain its value as value.
Set option as the key on collectedOptions with its value as value
If not present on allCollectedOptions, set option as the key on allCollectedOptions with its value as value.
Add collectedOptions to executedEventsToOptions with hookEvent.
Execute subtask with collectedOptions, CLI arguments, and hookConfig and assign the result to result.
Add result to results.
Add hookEvent to executedEvents.
Supply results as the return result of executeHooks and resume execution of task
This discussion was converted from issue #140 on September 13, 2023 15:17.
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
General idea
Allow tasks to define which specific events they emit, and then perform the emitting within the main task.
Allow this task or other tasks to have special subtasks listening for such events, and when there is a match, the subtask is executed. The subtask is similar to a regular task except that:
The emitting task will begin execution but upon encountering a call to execute hooks, will wait for all identified subtasks to execute (including their prompts), and then can use their return values to determine an order for applying the results.
Motivation
Sometimes tasks interact in ways where it is desirable that a single task allows consumers and can be provided by its consumers with information that it can use to determine how to present.
Alternatives considered
This is similar in some regards to the notion of hooks in #52, but:
So, as opposed to my understanding of #52, this particular notion of hooks (or events) in this issue is not for a hook that is a convenient way to override an existing core behavior on a single per-task basis.
This approach could conceivably be applied to mrm-core to override core code behavior, allowing core itself to register events which tasks could use. However, since in this proposal we are collecting results from multiple tasks before applying, core events would likely not be suitable since different tasks would not necessarily want overrides applied (e.g., one task might want to transform JSON and another would not). It would I think be a better separation in most cases for a single task to manage responsibility. This would also offer the advantage that projects do not need to wait for changes to core to make extensible, interacting behaviors.
Sample use cases
readme
task to present a single reusable template in config which, while referencing all potential variables for where other tasks' badges might be inserted (e.g., for linting, testing, coverage, license info, etc.), can also be used regardless of the tasks currently in use.And they won't need to create the README in this manner first; the template would be able to create it in this sequence from the beginning.
rather than
Tasks like a Markdown or README task, could offer "md" as an extension, a TypeScript task could offer "ts", etc., and then the
eslint
task could provide a template or otherwise assemble the extensions in a task-specifiable order.And as with the previous example, there is no need for the user to edit the
package.json
ahead of time to specify the desired order; their task template could specify this ahead of time and be reused across project.Proposed API
Sketch of control flow
(Steps are in series.)
allCollectedOptions
task
:emits
events, perform these steps:emits
event be calledevent
task
:checkTask
checkTask
is found to register itself for defining an event of the same name asevent
.task
executedEventsToOptions
.task
callsexecuteHooks
, then pause execution and follow these steps:hookEvent
be the name of the event with whichexecuteHooks
is invokedhookConfig
be any additional config passed (as the second argument ofexecuteHooks
).results
.task
):checkTask
listens
oncheckTask
is found with a hook subtask that matcheshookEvent
:subtask
hookEvent
on theexecutedEventsToOptions
map.collectedOptions
collectedOptions
.option
ofsubtask
:option
is not present inallCollectedOptions
, obtainoption
interactively asvalue
.value
.option
as the key oncollectedOptions
with its value asvalue
allCollectedOptions
, setoption
as the key onallCollectedOptions
with its value asvalue
.collectedOptions
toexecutedEventsToOptions
withhookEvent
.subtask
withcollectedOptions
, CLI arguments, andhookConfig
and assign the result toresult
.result
toresults
.hookEvent
toexecutedEvents
.results
as the return result ofexecuteHooks
and resume execution oftask
task
is not complete.Beta Was this translation helpful? Give feedback.
All reactions