Numable authoring docsthe same content is available in the terminal: `numable docs <topic>`中文

methods — expression methods and the .df whitelist (generated)

$[method::(args)] only knows the 46 methods below. An unknown method name does not error — it silently evaluates to empty (the unit stays on the widget, the number vanishes), so check here before writing one. The argument count is a minimum; extra arguments are ignored. Usage lives in numable docs df and numable docs rcn.

Methods

Method Arguments (min count) Returns Notes
calc expression string(1) number | null Arithmetic and parentheses. Android returns a double, so an integer renders as 17.0; wrap a number bound for text in round::. Any size string containing calc must be wrapped again in findNotEmpty::, otherwise a null result leaves a bare pt and the whole widget fails. Leading zeros are read as decimal (07 is 7, not octal) on iPhone, Android, HarmonyOS and desktop alike, so there is no need to run the value through parseNumber:: first; surrounding spaces are trimmed too. Only decimal is accepted: a form like 0x10 cannot be read and the whole expression comes back empty
urlEncode string(1) string Always run a dynamic segment through this before splicing it into a URL
urlDecode string(1) string It turns + into a space before decoding
base64Encode string(1) string
base64Decode string(1) string
get object, path(2) any Reads a value out of an object by path, and the path may itself be a variable: $[get::(${resp.rates},${q})] is the right way to say "take the entry the user picked". A ${} inside a method argument can only see keys already landed in the flow (an action's id result, or a key from op:set) — it cannot see depends inputs; land an input with op:set first, then use it
if condition, value if true, value if false(3) any All three arguments are required; do not feed the number it returns straight into calc::, land it first
eq value A, value B(2) boolean If both sides convert to numbers they are compared as numbers: eq::("00","") and eq::(empty,0) are both true. Always test for emptiness with the sentinel $[if::(eq::(findNotEmpty::(${x},none),none),0,1)] (not length::, which returns 0 for any number)
ne value A, value B(2) boolean Same numeric comparison rule as eq::
gt value A, value B(2) boolean Always false if either side is not a number
lt value A, value B(2) boolean Always false if either side is not a number
ge value A, value B(2) boolean Always false if either side is not a number
le value A, value B(2) boolean Always false if either side is not a number
or condition… (any number)(1) boolean Takes every argument
and condition… (any number)(1) boolean Takes every argument
floor number(1) number | null Android returns a double; wrap in round:: before putting it in text
round number(1) number | null Android returns a double
ceil number(1) number | null Android returns a double
min number… (any number)(1) number | null Android returns a double
max number… (any number)(1) number | null Android returns a double
parseNumber value, pattern(2) string | null Pattern grammar: 0 = integer (truncate toward zero); 0.00 = exactly two decimals; 0.## = up to two; a , in the integer part (e.g. #,##0.00) adds thousands separators. Format numbers before they reach the widget; large values need grouping or a smaller font or they overflow the widget edge
formatDate timestamp, format string(2) string | null Tokens are yyyy MM dd HH mm ss. An empty string renders as a fake 1970 time, so wrap it in a findNotEmpty:: sentinel. Multiply a second-precision timestamp by 1000 first. ⚠️ It formats in the device's own time zone (the same on iPhone, Android, HarmonyOS and desktop): one timestamp renders differently on machines in different zones, which is usually what you want ("what time is it here")
parseDate text, format string(2) number | null The only cross-platform-safe format is plain tokens plus - : / and spaces; letters (such as T or Z) make the whole parse fail on iOS/Android, so cut the string clean with subString:: first. ⚠️ It parses in the device's own time zone: most APIs hand you UTC (2026-09-08T12:00:00Z), and feeding that in straight makes it be read as local time — the timestamp comes out a whole time zone off, with no error. For a UTC string, either subtract the offset first or take an epoch timestamp from the source instead
random none(0) number A random number between 0 and 1; do not use it on a widget, it makes the cache and the renders disagree
md5_32 string(1) string 32-character lowercase digest
md5_16 string(1) string 16-character digest
length string | array | object(1) number It returns 0 for a number, so gt::(length::(a number),0) cannot answer "is there a value" — land an explicit flag in the flow instead; length::(number) also still differs across platforms, so only use it as a failure test on string fields
replaceAll source, regex, replacement(3) string The second argument is read as a regular expression, so a pipe and similar symbols cannot be used as separators — use an ordinary character such as ~
subString source, start, end(3) string Cuts by code point, and clamps to the bounds when they are exceeded
toLowerCase string(1) string
toUpperCase string(1) string
endsWith source, suffix(2) boolean
matches source, regex(2) boolean An invalid regular expression returns false rather than raising an error
startsWith source, prefix(2) boolean
echo any value(0) the value unchanged Returns its input as is, commonly used to land the result of an expression into a key
connect fragment… (any number)(1) string It eats the spaces at both ends of every argument, and on Android a number joins as 17.0. To keep spaces, or to mix text and values, interpolate with ${} inside the txt text instead
split source, regex(2) string[] The second argument is read as a regular expression; do not use a pipe as the separator or the whole string is split character by character; trailing empty strings are dropped from the result
index string | array | object, index(2) element | null Takes an element by index: a string by code point, an array by position, an object by insertion position; a negative index returns null. To read an object by key use get::, not index:: (passing a string key silently yields empty). Nested subscripts like ${a[${i}]} are not supported — writing one silently yields empty and overwrites the default parameter
contains source, substring(2) boolean A plain substring test, not a regular expression
findNotEmpty candidate… (any number)(0) the first non-empty value The workhorse fallback: any size string containing calc:: must be wrapped in it, and time anchors and colors should fall back to a literal through it too, or an empty value makes the block disappear or the whole widget fail to render
sum number… (any number) | array(1) number Returns 0 when there are no numbers. An array must be written as a real array literal, not stuffed into a method argument
pluck array, path (optional)(1) array Picks one column out of an array of objects; anything that is not an array comes back unchanged
join array, separator (optional)(1) string The separator defaults to an empty string
mapField array, source column, lookup table, new column, default (optional)(4) array | null Returns a new array (the input is untouched): each object row is shallow-copied and gets new column = table[row[source column]], or the default when there is no match (empty string if no default is given); non-object elements are kept as-is; a first argument that is not an array gives empty. Lookup keys: strings as-is (not trimmed), integers without .0, null / missing as an empty string, booleans as true / false
groupSum array, key column(s) (array or one column name), value column, weight column (optional)(3) object | null Groups by the key column(s) and sums value × weight; several key columns give nested objects whose leaves are numbers. Values and weights are trimmed and parsed as decimals; anything unparseable counts as 0. Results are rounded with Math.round(x × 1e6) / 1e6. An empty array gives {}; a non-array, an empty key array or an empty key string gives empty; an empty weight column counts as not given. Store the key-column array in a variable with op:set first and pass that — never write commas inside the argument. Key order is not guaranteed
convertSum amount table, rate table, target currency (optional)(2) number | null Σ amount[currency] / rate[currency], counting the target currency itself as 1; currencies with a 0 amount are skipped. If any currency has no rate (or a rate ≤ 0) the whole result is empty — better to show -- than to undercount. An empty or all-zero amount table gives 0. The result is rounded with Math.round(x × 1e6) / 1e6. The amount table is usually a groupSum grouped by currency

Global rules

What may appear in a .df

A data flow accepts only the items below; anything else (especially ui.* / nav.* / toast) is rejected at packaging time.

Category Allowed
action cancel error finish sleep request clearCookie htmlParse xmlParse log resultfilter resultFilter data.get data.set data.remove data.has data.keys data.getAll data.merge data.clear credential.state
operation (op key) if for forEach set remove include
composite (in the action slot) sequential concurrent
explicitly forbidden showLoading hideLoading toast plus every App-injected action (ui.* nav.* xpage.* widget.* singleValue startPageForResult installBundle)