Lanka Lanka docs

Scripts

A script calculates and changes variables. The "Script" step runs it.

The "Script" step in the editor

Under the script field, "Test run" shows what would change. It saves nothing.

Syntax

Every line assigns a value: variable = expression. A line that starts with # is a comment.

# Without a prefix a variable lives while the conversation lasts
options = filter(app.slots, item.status == "free")
labels = map(options, item.time)

# user.* stays with the visitor for good
user.score = default(user.score, 0) + 10
user.level = user.score > 100 ? 2 : 1

# app.* is the bot's shared data
app.total_plays = default(app.total_plays, 0) + 1
  • Values can be numbers, strings in quotes "…", true, false, null, lists [a, b] and objects {key: value}.
  • A string in backticks fills values in: `${item.name} ×${item.qty}` gives Shoes ×2. Any expression goes inside ${…}. An empty value fills in as nothing.
  • An expression may go on over several lines while a bracket is open.
  • A comment takes a whole line. A comment at the end of a line of code does not work.
  • A list element is items[0] or items.0. The size of a list or an object is list.size.
  • A variable nothing was assigned to yet is null. default(x, fallback) gives a fallback value.
  • == compares strictly: 1 == "1" is false.

Namespaces

The prefix before a variable's name says where it lives and for how long.

Variable What it is
name or session.name Conversation variables. A name without a prefix writes and reads here. They go away when the conversation ends.
user.name One visitor's state, for good. Read and write. Steps save answers here: input, choices, polls.
app.name Data shared by all visitors. Read and write. Counters, a catalog, a schedule.
temp.name Variables of one script. They live while it runs and are saved nowhere.
platform.* Telegram's data about the person and the message being handled. Read only. See below.
initiator.* Who started this flow through "Notify" or "Announce": user_id, name, username. Read only. Empty in an ordinary flow.
secret.* The bot's secrets from "Bot settings → Secrets": API keys, passwords. Read-only, and only inside a request: fetch, page_meta, save_image.
  • A field inside an object cannot be changed directly: user.cart.qty = 1 does not work. Build the object again, or change a list element with update_where.
  • Two chats can change app.* at the same time. Neither change gets lost.
  • Names starting with _ are reserved.
  • A rule of thumb: keep what the person entered in user.*, and what a script calculated in conversation variables.

Operators

What Operators
Arithmetic + - * / %
Comparison > < >= <= == !=
Logic && || !
A condition in one expression user.x > 5 ? "high" : "low"
Joining strings "Hello, " + platform.first_name

+ joins when either side is a string. Otherwise both sides must be numbers.

Functions

Math

Function What it does
min(a, b, ...) max(a, b, ...) Minimum and maximum
abs(x) Absolute value
floor(x) ceil(x) round(x, decimals?) Rounding down, up and to the nearest, to the given number of decimals
sqrt(x) pow(x, y) Square root and power
clamp(val, min, max) Keep a number within a range

Strings

Function What it does
len(s) Length of a string or a list
upper(s) lower(s) trim(s) Upper case, lower case, no spaces at the ends
contains(s, sub) Whether a string contains a substring
starts_with(s, prefix) ends_with(s, suffix) Whether a string starts or ends with this text
substr(s, start, len?) Cut out a substring
replace(s, from, to) Replace every occurrence
split(s, sep) Split a string into a list by a separator

Lists

Function What it does
count(list) Number of elements
sort(list) unique(list) The list sorted, and the list without repeats
join(list, ", ") List → string
append(list, item) Add an element to the end of a list
sort_by(list, "key", "desc") Sort by a field; "asc" ascending, "desc" descending
take(list, n) The first n elements
slice(list, start, count) A part of a list from position start (counting from 0)
last(list, n) The last n elements, in the same order
sum(list) Sum of numbers
nth(list, i) An element by its position; outside the list, null

Lists with item

In these functions the second argument is an expression in which item is the current element.

Function What it does
filter(list, item.status == "free") Keep the elements the expression holds for
map(list, item.time) Collect a value from every element
flat_map(list, item.slots) Like map, but the lists from every element merge into one
find(list, item.id == 5) The first matching element, or null
update_where(list, item.id == 5, "status", "busy") Change a field in the matching elements

These calls cannot be nested in one another's condition.

Dates

Dates are ISO strings that start with YYYY-MM-DD.

Function What it does
add_days(date, n) Move a date by n days; the result looks like "yyyy-MM-dd"
get_iso_day(date) Day of the week: 1 is Monday … 7 is Sunday
format(date, "dd.MM") Formatting with date-fns tokens: dd, MM, yyyy, HH:mm

Conversion and checks

Function What it does
num(x) str(x) bool(x) To a number, a string or a boolean; num fails when x is not a number
to_num(x, fallback) A number, or fallback when x is not a number
is_num(x) is_str(x) is_bool(x) is_null(x) Return true or false; is_null is also true for a variable that does not exist yet
default(x, fallback) fallback when x is null; 0 and "" stay as they are

Calling other services

fetch calls another service over the internet.

temp.resp = fetch("https://api.example.com/items", {method: "POST", body: {q: 1}, cache: 60, timeout: 10})
user.saved = temp.resp.status == 200 ? temp.resp.body.id : null
  • fetch takes the whole right-hand side of a line. Its result must go to temp.x (gone after the script) or session.x (kept for the conversation).
  • method, headers and body work as in any HTTP request. An object in body is sent as JSON, a string as it is.
  • timeout is how many seconds to wait for an answer: 5 unless set, 30 at most.
  • cache is how many seconds to keep a successful answer, an hour at most. The cache is shared by everyone who makes the same request. It suits a schedule or a catalog, never a booking.
  • The result is {status, body, error}. body is parsed JSON or text. When the request did not get through, status is null and error says why.
  • A failed request is not a script error and does not lead to the "+ Error step" branch. Check temp.resp.status == 200 and branch with a "Condition" step.
  • While a request runs, the person sees "typing…". Neighbouring requests that do not depend on each other run in parallel, up to 6 per script.

Secrets

Do not write an API key into a script in plain text: save it as a secret and read it in a request as secret.API_KEY. More on the Secrets page.

Page data and pictures

page_meta and save_image follow the same rules as fetch.

temp.page = page_meta(link)
temp.photo = save_image(temp.page.image)
app.catalog = append(app.catalog, {id: "p1", name: temp.page.title, image: temp.photo.url})
  • page_meta(url) reads what a page says about itself: {status, title, description, image, images, url, site, type, extra, error}. images holds up to 10 of the page's pictures, the main one first.
  • save_image(url) copies a picture into the bot's media: {url, urls, error}. It also takes a list, up to 10 pictures, each up to 20 MB. A test run does not save the picture.

Platform variables

Read only.

Variable What it is
platform.user_id The person's Telegram ID (a number)
platform.first_name First name
platform.last_name Last name
platform.full_name First and last name; either may be missing
platform.username @username
platform.language_code Language code (uk, en, …)
platform.is_premium Whether the person has Telegram Premium (true / false)
platform.first_seen When the person first wrote to the bot (ISO 8601)
platform.last_seen When the person last did anything in the bot (ISO 8601)
platform.message_text Text of the message being handled
platform.start_param The data after the dash in a link to a flow; present only in reply to /start, and the conversation it opened keeps it as session.start_param
platform.now The current moment, ISO 8601

Limits

What How much
Expression length 1024 characters
Statements (a fetch over several lines counts as one) 50
Script length 4096 characters
List length 500
Elements in one {…} or […] 50
fetch wait 5 s unless set; 30 s at most
fetch answer 1 MiB
fetch cache 1 hour