-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Runtime: allow re-usable functions across a workflow #648
Comments
Quick brainstorm of options:
|
Allow re-usable functions across a workflowI align more with the workflow.functions idea. Workflow level functionUsers have a single place(maybe a file) where they define all their utility functions that can be accessed anywhere in a workflow. Job level functionWhen users want to define simple functions to use in a single job.
function kebabCase(name) {
return name.replace(/\s/g, '-')
}
fn(state => {
state.data.name = "openfn new kit"
return state;
})
fn(state => {
state.data.kebabName = kebabCase(state.data.name);
return state;
}) I think allowing both workflow level and job level functions will be vital. Other suggestions I don't align with
|
It works by calling |
Good points about hide-and-seek! I generally agree with you, but I'm really worried about the cost of supporting But let's dig into it a bit deeper. Functions objectWe could do this:
If we only think about the CLI and workflow.json, this is the most intuitive approach. And to be fair lightning could easily write the functions to the state object nicely. But it's pretty poor UX. No-one is ever going to write a function directly in json, and having one function per file is also pretty unpleasant. And I guess that file would have to export default or something, which is again a limitation. But it would at least be easy to inject those functions into the runtime context, so that's a plus. Functions moduleAlternatively I guess we'd do this:
Where functions points to a js module. The module must have named exports. All exports are injected in the runtime global scope.
Since it's just a js file, the functions are unit testable, so that's nice. If Lightning were to ever provide a UI for these functions, it could serialize the module into This feels like a better approach? General assumptions
Compiler noteIf we're going to inject anything in the global runtime context, the compiler needs to know about it. Otherwise when it sees an undeclared global variable, it'll assume it belongs to the adaptor and try and import it, which breaks everything. |
The Problem
It's common in workflows to want to re-use the same helper function in multiple steps.
For example, let's say we create our own id-generator or date-formatter, or data converter.
We used to allow functions to be written to state and used in multiple steps. I think that might still work? [citation needed]. It should break in-between steps really. Even if it's works its not a great approach.
Solutions
workflow.functions
Declare a function somewhere on the workflow body. Maybe we can have
workflow.fns
as a peer ofworkflow.steps
. It probably references a file, rather than defines functions inline.I'm not keen on this idea because it need s special UI support in Lightning and I just don't think we have the resources.
Make functions global
We could say: if you declare a function in a step, that function will automatically be available to the rest of the workflow.
This would either be through a function declaration
function generateId() {}
or possibly an exported function declaration (are arrows allowed?). Exported functions would open a door to unit testing too. Of course, we could use compiler magic to auto-export top-level functions.I have no idea how we'd implement this technically.
Do we have to pre-parse the workflow, find all functions, extract their source, and set them into the runtime context? Sheesh, that sounds like a lot of work.
Alternatively, when a function is declared, we call a special runtime API to register it, and it's then available to all other functions downstream. This would be alright.
Use an API
We could provide a special API like
declare()
which takes a function declaration and a name as an argument. Then, just like the global functions thing, this function would be made available to all downstream steps.We'd have to inject the
declare
function from the runtime, just like we do with thedefer
function.This could be compiler magic again - if the
declare
function is a useful hook for implementation, then maybe the compiler can wrap all top level function declarations into declare cals.The text was updated successfully, but these errors were encountered: