@parallelworks/workflow-parser
v0.8.0
Published
Workflow expression parser and pure workflow logic for Parallel Works ACTIVATE: the WASM expression evaluator, workflow-to-form conversion, log segment parsing, and run/matrix helpers
Readme
@parallelworks/workflow-parser
The pure workflow logic behind Parallel Works ACTIVATE: the ${{ }} expression
evaluator (compiled to WebAssembly), workflow-to-form conversion, run and matrix
status helpers, and workflow log commands. No React, no network calls, no ACTIVATE
API client: everything here is a function over workflow YAML, form values, or
log text.
With @parallelworks/ui
The ui package's workflow form, graph, editor and log viewer take these
semantics as an engine on UIProvider:
import { UIProvider } from '@parallelworks/ui'
import { createWorkflowEngine } from '@parallelworks/workflow-parser'
const engine = createWorkflowEngine()
<UIProvider engine={engine}>{app}</UIProvider>createWorkflowEngine({ wasmUrl }) takes the same wasmUrl override as
initializeParseStringsOfObj.
Expression evaluation
Workflow YAML may interpolate ${{ inputs.region }}, ${{ org.foo }}, and
friends. The evaluator is the same implementation the backend runs, compiled to
WASM so the browser resolves expressions identically.
import {
initializeParseStringsOfObj,
parseStringsOfObj,
containsExprJS,
} from '@parallelworks/workflow-parser'
await initializeParseStringsOfObj()
const resolved = parseStringsOfObj({
inputs: { region: 'us-east-1' },
obj: workflowSchema,
orgVars: { bucket: { value: 'my-bucket' } },
})initializeParseStringsOfObj fetches parseWorkflow.wasm relative to the
module URL and instantiates it, so it requires a browser (or any environment
with fetch and WebAssembly.instantiateStreaming) and a bundler that emits
the binary as an asset. Pass wasmUrl to point it somewhere else, for example
a host serving a precompressed copy:
await initializeParseStringsOfObj({ wasmUrl: '/assets/parseWorkflow.wasm' })Until the runtime is ready parseStringsOfObj returns its input unchanged, so
callers can render before initialization completes and re-render after.
callWhenParserInitialized subscribes to that transition. containsExprJS is
a cheap pre-check that skips the WASM boundary for expression-free values, and
extractInputDeps reports which top-level inputs a schema references, so a form
can recompute only the fields an edit can affect.
Workflow forms
import {
convertToDynamicForm,
prepareSubmittableValues,
workflowHasUserInputs,
} from '@parallelworks/workflow-parser'convertToDynamicForm turns a workflow's on.execute.inputs schema into the
field tree a dynamic form renders; prepareSubmittableValues runs the reverse
trip, dropping fields the schema ignores and shaping the rest into a run
submission.
The form renderer supports optional presentation metadata at
on.execute.inputs.$meta.layout. Layouts use field references and nested
stack, grid, and section containers. References are local to the input
scope, so a group's layout belongs in items.$meta, a list's in
template.$meta, and a wizard page's in options.$meta. Conversion preserves
this metadata unchanged, including across repeated conversions; value paths
and submission behavior remain tied to the input definitions.
The workflow JSON schema defines the layout contract, including responsive
columns, relative column weights, spans, and spacing. Use a form-renderer
version with explicit layout support alongside this schema. The existing
width and anchor-below hints remain valid, while an explicit layout takes
precedence within its scope.
Runs, matrices, and logs
import {
computeMatrixAggStatus,
detectMatrixGroups,
isRunActive,
canCancelRun,
parseWorkflowCommand,
} from '@parallelworks/workflow-parser'detectMatrixGroups groups expanded matrix jobs back under their original job,
and computeMatrixAggStatus folds a group's statuses into one status plus a
human label. parseWorkflowCommand recognizes the ::error:: and ::group:: annotation
lines a workflow emits to structure its own output.
