Zum Inhalt springen
Developer Preview — APIs and language features may change before 1.0

Expressions

Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.

mashin has a built-in expression language used inside compute steps, decide conditions, and ${...} interpolation in task strings. It is JavaScript-inspired: if you know JS, you already know most of it. The key difference is that expressions are pure. There are no I/O primitives, no fetch(), no console.log(). Expressions compute; machines act.

+ - * / %
== != > < >= <=

In decide steps, you can also use natural-language operators: is, is not, is greater than, is less than, is at least, is at most.

&& || !

Natural-language: and, or, not.

condition ? valueIfTrue : valueIfFalse

Bind intermediate values with let. Bindings are scoped to the current step:

compute analyze
let count = input.items.length
let total = input.items.reduce((sum, x) => sum + x.amount, 0)
let average = total / count
{count: count, total: total, average: average}

The last expression in a step is its return value.

Reference What it accesses
input.<field> Machine input fields
steps.<step_name>.<field> Output from a previous step
context.<key> Execution context values
state.<field> Machine state (reactive machines)
event.<field> Incoming event data (in subscribes handlers)

Dot access and bracket access both work: input.name and input["name"] are equivalent.

Inside with task strings (and any string using ${}), expressions are evaluated and inserted:

ask classify, using: "anthropic:claude-sonnet-4-6"
with task "Analyze this order.\n\nCustomer: ${input.customer_name}\nTotal: $${input.amount}\nItems: ${input.items.length}"

Arrays support the standard functional methods:

compute transform
let names = input.users.map(u => u.name)
let active = input.users.filter(u => u.active)
let total = input.scores.reduce((sum, s) => sum + s, 0)
let found = input.items.find(i => i.id == input.target_id)
let has_admin = input.roles.includes("admin")
{
names: names,
active_count: active.length,
total_score: total,
target: found,
has_admin: has_admin
}
Method Description
.map(fn) Transform each element
.flatMap(fn) Map then flatten one level. A callback result that is not a list counts as one element, so [1, 2].flatMap(x => x) is [1, 2] and a null result contributes one null
.filter(fn) Keep elements that match
.reject(fn) Remove elements that match
.reduce(fn, init) Accumulate a value
.find(fn) First matching element
.findIndex(fn) Index of the first matching element (-1 if none matches)
.some(fn) / .any(fn) True if any element matches
.every(fn) True if all elements match
.includes(val) Check if value exists
.indexOf(val) Index of first occurrence (-1 if not found)
.sort() Sort elements
.sortBy(fn) Sort by a key function
.reverse() Reverse order
.unique() / .uniq() Remove duplicates
.uniqueBy(fn) Deduplicate by key function
.groupBy(fn) Group into object by key function
.flat() Flatten one level
.concat(other) Concatenate two arrays
.join(sep) Join elements into a string
.take(n) First N elements
.drop(n) All but first N elements
.chunk(n) Split into chunks of size N
.zip(other) Pair elements from two arrays
.slice(start, end) Sub-array by index range
.at(index) Element at index
.count(fn) Count elements matching predicate
.sum() Sum of numeric elements
.min() / .max() Minimum / maximum element
.first() / .last() First / last element
.length Number of elements
Method Description
.toUpperCase() / .toLowerCase() Case conversion
.trim() Remove leading/trailing whitespace
.trimStart() / .trimEnd() Remove whitespace from one end
.split(separator) Split into array
.replace(from, to) Replace first occurrence
.replaceAll(from, to) Replace all occurrences
.startsWith(s) / .endsWith(s) Check prefix/suffix
.includes(s) Check if substring exists
.padStart(n) / .padEnd(n) Pad to length
.repeat(n) Repeat N times
.substring(start, end) Extract substring
.match(pattern) Regex match
.test(pattern) Regex test (returns boolean)
.length String length

Build objects with {} syntax. Use spread to merge:

compute merge
let base = {status: "active", created: DateTime.now()}
let details = {name: input.name, email: input.email}
{...base, ...details}

Access nested fields with dot notation: steps.analyze.results[0].name.

Objects carry their operations as methods. There is no Object namespace; writing Object.keys(map) is an error that points you to the method form.

Method Description
map.keys() Array of keys
map.values() Array of values
map.entries() Array of [key, value] pairs
map.merge(other) Merge two objects (other overrides)
map.has(key) Check if key exists
map.delete(key) Remove a key

Numbers carry their operations as methods; two-value max and min take a list receiver. There is no Math namespace; writing Math.abs(x) is an error that points you to the method form.

Method Description
x.round() Round to nearest integer
x.round(n) Round to N decimal places
x.ceil() / x.floor() Round up / down
x.abs() / x.sign() Absolute value / sign
x.pow(exp) Exponentiation
x.sqrt() Square root
[a, b].min() / [a, b].max() Minimum / maximum
list.sum() Sum of a numeric list
compute stats
let rounded = input.price.round(2)
let biggest = [input.a, input.b].max()
{rounded: rounded, biggest: biggest}

Format values for display with the format namespace. Returns strings, not numbers.

compute display
let price = format.number(input.amount, {decimals: 2}) // "1,234.50"
let rate = format.number(input.percentage, {style: "percent"}) // "18%"
let date = format.date(input.timestamp) // "Jun 9, 2026"
{price: price, rate: rate, date: date}
Function Description
format.number(x) Format with thousands separator
format.number(x, {decimals: n}) Fixed decimal places
format.number(x, {style: "percent"}) Percentage format
format.date(iso) Short date format
format.date(iso, {style: "time"}) Time only
Function Description
DateTime.now() Current ISO 8601 timestamp
DateTime.today() Current date
DateTime.parse(str) Parse ISO string
DateTime.diff(a, b) Difference between datetimes
DateTime.add(dt, amount) Add duration
Function Description
JSON.parse(str) Parse JSON string to object
JSON.stringify(obj) Convert object to JSON string
compute format_price
let amount = input.price
{
display: amount > 1000
? "$" + (amount / 1000).round(1) + "k"
: "$" + amount.round(2),
tier: amount > 10000 ? "enterprise" : amount > 1000 ? "business" : "starter"
}
compute reshape
let grouped = input.orders.reduce((acc, order) => {
let key = order.status
let existing = acc[key] || []
return {...acc, [key]: [...existing, order]}
}, {})
{by_status: grouped, total: input.orders.length}
compute score_candidates
let scored = input.candidates.map(c => ({
...c,
score: c.experience * 0.4 + c.test_result * 0.6
}))
let qualified = scored.filter(c => c.score >= 70)
{
qualified: qualified,
qualified_count: qualified.length,
best: qualified.reduce((best, c) => c.score > best.score ? c : best, qualified[0])
}
  • compute steps: the entire body is an expression
  • decide conditions: when <expression>
  • with task strings: ${expression} interpolation
  • Step configuration: values in returns, assuming, field defaults

Write a machine that accepts a list of numbers and uses a single compute step to return the count, sum, average, minimum, and maximum. Use let bindings for clarity.