Mapping values
Values flow between Tasks and Wires. shape transforms a value between them — picking a piece of it, deriving a new one from it, or merging several into one. Its input is one or several sources. The transform lives in shape, not in fn.
Inside a context
Section titled “Inside a context”shape works in both run.context and enabled.context.
import { compose, createTask, shape } from "@grlt-hub/app-compose"
const user = createTask({ name: "user", run: { fn: () => ({ name: "John", role: "admin" }), },})
const greeting = createTask({ name: "greeting", run: { // run.context context: { name: shape(user.result, (u) => u.name.toUpperCase()), }, fn: ({ name }) => console.log(`Welcome back, ${name}`), },})
const adminPanel = createTask({ name: "admin-panel", run: { fn: () => console.log("Admin panel ready"), }, enabled: { // enabled.context context: { isAdmin: shape(user.result, (u) => u.role === "admin"), }, fn: ({ isAdmin }) => isAdmin, },})
compose() .step(user) .step([greeting, adminPanel]) .run()Inside a Wire
Section titled “Inside a Wire”shape works in createWire.from.
import { compose, createTask, createWire, shape, tag } from "@grlt-hub/app-compose"
const userName = tag<string>("userName")
const user = createTask({ name: "user", run: { fn: () => ({ name: "John", role: "admin" }), },})
const greeting = createTask({ name: "greeting", run: { context: { name: userName.value, }, fn: ({ name }) => console.log(`Welcome back, ${name}`), },})
const userNameWire = createWire({ from: shape(user.result, (u) => u.name.toUpperCase()), to: userName,})
compose() .step(user) .step(userNameWire) .step(greeting) .run()Several sources
Section titled “Several sources”Pass an array or an object instead of a single source — either works:
import { compose, createTask, shape } from "@grlt-hub/app-compose"
const firstName = createTask({ name: "first-name", run: { fn: () => "John" },})
const lastName = createTask({ name: "last-name", run: { fn: () => "Doe" },})
const fullNameShape = shape( { first: firstName.result, last: lastName.result, }, (v) => `${v.first} ${v.last}`,)
// as an array// shape(// [firstName.result, lastName.result],// ([first, last]) => `${first} ${last}`,// )
const fullName = createTask({ name: "full-name", run: { context: { fullName: fullNameShape }, fn: console.log, },})
compose() .step([firstName, lastName]) .step(fullName) .run()Failure behavior
Section titled “Failure behavior”When shape fails, the downstream Task skips. Two cases:
- The source Task fails
- The
shapecallback throws an error
The rest of the composition runs as usual.