# Quillo > Quillo is a programming language for web apps. One `.qwe` file can hold the server's > routes, the HTML (written like JSX), components that run in the browser, and SQL on a > built-in SQLite. There is no package file, no build step and no JavaScript to write. > `quillo run` serves the program; `quillo check` checks it without running it. This is for Quillo 0.7.0. Features marked *(since 0.7)* are new in it. On 0.6.0, read https://github.com/quillolang/quillo/blob/v0.6.0/USERGUIDE.md and https://quillolang.org/v0.6.0/llms.txt instead. This file is for AI coding assistants. Quillo is new, so what you know from other languages will lead you wrong in a few places, listed below. Rules for working on a Quillo program: - After every edit, run `quillo check` (in the program's folder, or `quillo check main.qwe`). It finds syntax errors, wrong types, misspelled fields, missing `import`s, JavaScript habits that mean something else here, and markup the browser would break. Fix what it says before you go on. - `quillo fix` *(since 0.7)* writes the `import` lines a program's files need. - `quillo run --watch` serves at http://127.0.0.1:8080 and reloads on each save. - Do not invent builtins. The list is at the end of this file and in https://quillolang.org/docs/standard-library/. When unsure, `quillo repl` answers quickly: `echo 'split("a,b", ",")' | quillo repl`. - Do not add `package.json`, a bundler or a framework. A page's components need nothing but the program. ## Files | File | Is | |---|---| | `main.qwe` | the program: what it opens, the files it uses, its routes | | `lib/*.qwe`, `ui/*.qwe` | its parts, by convention: helpers and server fns; views and components | | `migrations/NNN_name.sql` | the database's tables, run once each, in order, by `db.migrate("migrations")` | | `public/` | files served as they are (with a route: `route GET /assets/*path = files("public", path)`) | | `*.qwer`, `*.rs` *(since 0.7)* | Rust a program `use`s (`quillo install ` fetches a `.qwer` plugin from quillolang.org/plugins) | `quillo new my-app` *(since 0.7)* makes a program to start from (`--minimal` for a page and a component). ## The language in one screen ```quillo let n = 42 // let declares; = += -= reassign. No const, var, *=, ++ let price = 12.50m // a decimal: exact, for money let name = "Ada" // "..." and '...' are plain text; only `...` interpolates let hello = `Hello, ${name}` let xs = [1, 2, 3] let user = { name, role: "admin" } // { name } is { name: name } fn add(a: int, b: int = 10) -> int = a + b fn area(w, h) { let a = w * h a // a block gives its last expression; return only to leave early } let double = (x) => x * 2 let big = xs | filter((x) => x > 1) | map(double) // a | f(b) is f(a, b) let first_big = xs.filter((x) => x > 1).first() // x.f(y) is f(x, y) too let label = n > 0 ? "positive" : "not positive" let squares = for x in xs => x * x // for gives a list let kind = match user { { role: "admin" } => "staff" { role: str as r } => r _ => "nobody" } ``` - Values are immutable: `push`, `set` and `+` return new lists and maps, so write `xs = xs | push(4)` and `m = set(m, "k", v)`, or spread: `{ ...user, name: "Grace" }`. - `==` compares deeply and converts nothing: `1 == "1"` is false, `[1, 2] == [1, 2]` is true. - Only `null`, `false` and error values are falsy. **`0` and `""` are truthy**, so `name || "anonymous"` keeps an empty name: write `filled(name) ?? "anonymous"` *(since 0.7)*, and `count != 0 && `, not `count && `. - `/` is exact: `7 / 2` is `3.5`, `6 / 2` is `3`; `floor(7 / 2)` divides whole numbers. Ints are 64-bit and overflow is an error, never a wrap. - A field of `null` is `null`, so `user.address.city` needs no `?.` (there is none). - `a..b` is the ints from `a` up to, not including, `b`: `for i in 0..10 => i`. - Comments are `//` and `/* */`. A line break ends a statement; a line starting with `|`, `.method`, `&&`, `||`, `??`, `?`, `:` or `else` continues the one before. ## What Quillo does not have, and what to write | Not in Quillo | Write | |---|---| | `const`, `var` | `let` | | `function f() {}`, `def`, `func` | `fn f(x) = ...` or `fn f(x) { ... }` | | `class`, interfaces, enums | `type User = { name: str, role: "admin" \| "member" = "member" }`, and functions | | `try`/`catch`, `throw`, `raise` | errors are values: `return err("why")`, `f()?` passes one on, `f() ?? fallback` replaces it | | `x in xs`, `k in m` | `contains(xs, x)`, `has(m, k)` | | `break`, `continue` | `return` to leave; `filter` first to skip items | | `1 < x < 3` | `1 < x && x < 3` | | `x?.y` | `x.y` (a field of null is null) | | `===`, `**`, `++`, `*=`, `/=`, bitwise `& \| ^ << >>` | `==`, `pow(a, b)`, `x += 1`, `x = x * 2`, `bit.*` *(since 0.7)* (`\|` is the pipe) | | `and`, `or`, `not`, `if c then a else b` | `&&`, `\|\|`, `!`, `c ? a : b` or `if c { a } else { b }` | | `/regex/` literals | strings to `re.*`: `re.find_all(s, "@(\\w+)")` | | `yield`, generators | return a list | | `<>...` fragments | one element around the others | | `className` | `class` (`onclick={...}` *(since 0.7)* and `@click={...}` are both a handler) | | `m.name = v` | `m = { ...m, name: v }` (inside a component it sets an element's property) | Builtins are free functions that take the list, map or string first: | JavaScript or Python | Quillo | |---|---| | `xs.map(f)`, `xs.filter(f)`, `xs.find(f)` | `map(xs, f)`, `filter(xs, f)`, `find(xs, f)` (`null` when none) | | `xs.reduce(f, init)` | `reduce(xs, init, f)`: the start value first | | `Math.max(a, b)`, `max(a, b)` | `max([a, b])`: `max`, `min`, `sum` take one list | | `s.length`, `len(s)` | `len(s)`, counting characters | | `s.indexOf(x)` | `index_of(s, x)`: `null`, not `-1` | | `parseInt(s)`, `int(s)` | `int(s)`: an error value for text that is no number; `int(s) ?? 0` | | `s.replaceAll(a, b)` | `replace(s, a, b)` | | `xs.sort((a, b) => a.n - b.n)`, `sorted(xs, key=...)` | `sort_by(xs, (x) => x.n)` | | `x.toFixed(2)`, `round(x, 2)` | `round(x, 2)` | | `JSON.parse`, `JSON.stringify` | `json.parse`, `json.stringify` | | `encodeURIComponent(s)` | `url_encode(s)` | | `console.log`, `print` | `print(x)` | ## Types and records Annotations are optional, checked when a function is called and by `quillo check`: `int float dec num str date bool list map html fn response any`, `list`, `{ title: str, note: str? }`, unions `int | str`, `str?` for "or null". `-> T` is what a function gives, `! E` what its errors hold. ```quillo type User = { name: str, email: str, role: "admin" | "member" = "member", tags: list = [] } let ada = User({ name: "Ada", email: "ada@example.com" }) // checked, defaults filled let bad = User({ name: "Ada" }) // err("User: `email` is missing"); quillo check reports it ``` `User(v)` drops fields the record does not have, so what a client sends cannot add `is_admin`. A type's name is `User` or `OrderLine` (not `ID`, not `user`). ## Errors ```quillo fn parse_age(s: str) -> int ! str = match int(s) { int as n if n >= 0 => n _ => err(`bad age: ${s}`) } fn next_year(s: str) = parse_age(s)? + 1 // ? returns the error from this function let age = int("x") ?? 18 // ?? replaces null or an error ``` `is_err(r)` tests, `r.error` reads the message. An error a statement drops is logged; an error from `db.exec` should be passed on with `?`, or a transaction may keep half its work. Inside a lambda, `?` leaves the lambda only: use a `for` loop to stop at the first failure. ## Program structure ```quillo // main.qwe db.open("app.db") db.migrate("migrations") use "lib/notes.qwe" // runs the file once and takes all its names use "ui/page.qwe" route GET / = ``` ```quillo // ui/note_list.qwe: takes only what it calls import lib/notes.qwe use load_notes, add_note ``` - Paths count from the main file's folder, in every file: `use "lib/x.qwe"` in `ui/a.qwe`, never `"../lib/x.qwe"`. - A file that calls a name from another file takes it: `import path use name` *(since 0.7)*, or the whole file with `use "path"`. `quillo fix` writes these lines for you. - Start each file with a comment saying what it holds. ## Routes ```quillo route GET /hello = "Hello" // text route GET /api/todos with db = db.query("select * from todos") // a list or map is JSON route GET /todos/:id(int) with db { let t = db.one("select * from todos where id = ?", id) t ?? respond(404, "no such todo") } route GET /search ? { q: str, page: int = 1 } = search(q, page) // query pattern route POST /todos { form: { text: str } } with db { db.exec("insert into todos (text) values (?)", text)? redirect("/") } route POST /api/users { json: User } = respond(201, save(json)) // body made a User route GET /assets/*path = files("public", path) ``` - A route gives: HTML (200 html), a string (200 text), a map, list, number or bool (200 JSON), `null` (204), `respond(status, body, headers)`, `redirect(url)`, `file(path)`, `stream(...)` or `events(...)`. - `request` has `path`, `query`, `form`, `json`, `body`, `headers`, `cookies`, `files`, `ip`. Prefer patterns in the route line to reading `request` by hand: a route whose pattern does not match lets the next route try. - `reply 401 "Log in"` ends the request from anywhere, a helper too. - Sessions: `set_session({ user })`, `session().user`, `end_session()`. Cookies: `set_cookie`, `delete_cookie`. ## HTML, views and components ```quillo view Card(title: str, children) =

{title}

{children} component Counter(start: int = 0) { state count = start // state: assigning it updates the page let double = count * 2 // recomputed when count changes
{count} (x2 = {double})
} route GET / = ``` - HTML is a value, written like JSX: `{expr}` interpolates and escapes; `raw(s)` is trusted HTML; `` is shorthand for class and id; `class={ok && "ok"}` leaves the attribute out when false or null; `{for t in todos =>
  • {t.text}
  • }` renders a list. - A `view` is made on the server only. A `component` is made on the server and resumes in the browser; nothing else on the page needs JavaScript. - Events are `onclick`, `onsubmit`, `oninput`, `onchange` (or `@click` and the rest), given a lambda. What a person changes is two-way by itself when it shows a state *(since 0.7)*: ``, `checked={done}`, `
    `, a player's `volume={v}`. A handler of the input's own, or `readonly`, keeps it one way. - `style css`...`` at the start of a component's body is CSS for its elements only. - A `server fn` is a function the browser calls over HTTP. In a component it is awaited for you and returns an error value if it fails: ```quillo server fn add_task(text: str) -> list ! str with db { if trim(text) == "" { return err("a task needs some text") } db.exec("insert into tasks (text) values (?)", text)? db.query("select * from tasks order by id") } server fn list_tasks() -> list with db = db.query("select * from tasks order by id") component Tasks() { state items = live(list_tasks) // runs again when the tasks table changes, on every page state draft = "" state problem = null
    { let r = add_task(draft) if is_err(r) { problem = r.error } else { draft = "" } }}> {problem &&

    {problem}

    }
      {for t in items ?? [] =>
    • {t.text}
    • }
    } ``` - `state x = load()` with a `server fn` loads on the server while the page is made, so the page arrives with its data. - A statement in a component body that reads state runs again when that state changes; what it starts (`every(ms, f)`, a listener) stops when it no longer runs. There is no `useEffect`, no dependency list and no `useMemo`: `let` is already derived. ## Database ```quillo db.open("app.db") // SQLite, built in; postgres://... works too db.migrate("migrations") // migrations/001_init.sql, 002_..., each run once let rows = db.query("select id, text from todos where done = ? order by id", 0) // list of maps let one = db.one("select * from todos where id = :id", { id: 7 }) // a map or null let r = db.exec("insert into todos (text) values (?)", "Write docs") // { changes, last_id } db.transaction(() => { db.exec("update accounts set cents = cents - ? where id = ?", 500, 1)? db.exec("update accounts set cents = cents + ? where id = ?", 500, 2)? { moved: 500 } // an error above rolls it all back }) ``` - Always pass values as `?` or `:name` placeholders; never build SQL with `+` or `${}`. - A row is a map: `select a.id, b.id` leaves one `id`, so name columns apart with `as`. - `with db` on a function says it uses the database; a function with `with` may do only what it declares (`db`, `http`, `fs`, `env`, `time`, `random`, `net`). Routes and route groups take it too *(since 0.7)*, before the body: `route GET /report with db = ...`, `routes /admin | signed_in with db { ... }`. ## Before you finish - `quillo check` passes with no errors, and its warnings are read. - Every error a statement can give is passed on (`?`), replaced (`??`) or taken (`let _ =`). - `0` and `""` were not used as false. - No builtin was guessed: each is in the list below. ## Builtins All 348 of them. A name with a dot is a module's (`db.query`). ### Text - `contains(x, y)`: Whether `x` has `y`: text in a string, an equal item in a list, a key in a map. - `upper(s)`: `s` in capitals, for all of Unicode: `"straße"` is `"STRASSE"`. - `lower(s)`: `s` in small letters, for all of Unicode. - `normalize(s, form)`: `s` in one Unicode form, `"NFC"` unless given (`"NFD"`, `"NFKC"`, `"NFKD"`): text that looks the same compares the same. - `trim(s)`: `s` without the whitespace at both ends. - `filled(x)`: `x`, or null for `""`: `filled(name) ?? "anonymous"` replaces a missing or blank name. `0`, `false` and lists stay as they are. - `split(s, sep)`: `s` cut at each single `sep`, a space unless given; `""` gives the characters. - `join(xs, sep)`: The items as text with `sep` between, nothing unless given. - `starts_with(s, prefix)`: Whether `s` begins with `prefix`. - `ends_with(s, suffix)`: Whether `s` ends with `suffix`. - `replace(s, from, to)`: `s` with every `from` replaced by `to`: plain text, not a pattern (that is `re.replace`). - `repeat(s, n)`: `s` written `n` times; a negative `n` is an error. - `slice(x, start, end)`: Part of a list or string, up to but not including `end`; negative positions are from the end. - `index_of(x, y)`: The position of `y` in a list or string, counting from 0, or null if it is not there. - `markdown(text, options)`: Markdown as `html`, safe for visitors' text; option `html` keeps its HTML, `inline` stays in a line. - `accept_calls(options)`: How calls from other services are taken: `keys` for each caller, `shared`, `jwt`, `client_cert` (a proxy's header), `check`. - `classes()`: The classes the program's markup writes, sorted: `.name`, `class="..."`, the text in `class={...}`, `class:name`; not those made from parts. - `files(folder, path, options)`: A folder served as a static host does: index.html, `/about` as about.html, 404.html; options `index`, `extensions`, `not_found`, `cache`. - `markdown_page(text, options)`: Markdown as a whole page, with a doctype, a `` and a title (option `title`, else the first heading); options `lang` and `html`. - `highlight(code, lang)`: `code` as escaped HTML, coloured for `lang`; an unknown `lang` gives it plain. ### Lists - `map(xs, f)`: A list of what `f` gives for each item. - `filter(xs, f)`: The items `f` is true of, in order. - `find(xs, f)`: The first item `f` is true of, or null. - `any(xs, f)`: Whether `f` is true of some item; false for an empty list. - `all(xs, f)`: Whether `f` is true of every item; true for an empty list. - `reduce(xs, start, f)`: Goes through the list with `f(total, x)`, `total` beginning as `start`; gives the last total. - `sum(xs)`: The items added up; `0` for an empty list, and a sum of decimals stays exact. - `min(xs)`: The least item of a list (not of several arguments), or null when it is empty. - `max(xs)`: The greatest item of a list (not of several arguments), or null when it is empty. - `sort(xs)`: `xs` ascending and stable; null, booleans, lists, or a string among numbers are an error. - `sort_by(xs, f)`: `xs` ascending by what `f` gives, stable; no comparator and no descending flag. - `reverse(x)`: A list or string the other way round. - `first(xs)`: The first item of a list, or null when it is empty. - `last(xs)`: The last item of a list, or null when it is empty. - `push(xs, x)`: A new list with `x` at the end; `xs` itself stays as it was. - `range(a, b, step)`: The ints from `a` up to but not including `b`; given one number, from 0 up to it. With a `step`, every `step`th, down if it is negative. - `enumerate(xs)`: `[index, item]` pairs, the index from 0. - `unique(xs)`: The first of each group of equal items, in order. - `flatten(xs)`: One level taken off: `[[1], [2, 3], 4]` is `[1, 2, 3, 4]`. - `zip(a, b)`: Pairs of items from both lists, as long as the shorter. - `take(x, n)`: The first `n` items of a list, or characters of a string; all of them if there are fewer. - `drop(x, n)`: A list or string without its first `n` items or characters. - `count(xs, f)`: How many items `f` is true of; without `f`, how many there are. - `group_by(xs, f)`: A map from each key `f` gives, as text, to its items: `1` and `"1"` are one key. - `join_on(rows, others, key, other_key, as)`: Each row with its first match in `others` under `as`, or null; `other_key` is `key` unless given. ### Maps - `keys(m)`: The map's keys, as a list of text. - `values(m)`: The map's values, as a list. - `get(m, key, default)`: The value at `key`, or `default` (null unless given) when the map lacks it. - `has(m, key)`: Whether the map has `key`, even with a null value. - `set(m, key, value)`: A new map or list with `key` set; a map's keys are text, and an index past a list's end is an error. - `remove(x, key)`: A new list without the items equal to `key`, or a new map without that key. - `merge(a, b)`: A new map of `a` and `b`; where both have a key, `b`'s value. Two maps only. ### Values - `error(x)`: What an error value says, and null for any other value. - `run_after(ms, f)`: In the browser: calls `f` once, `ms` milliseconds on, unless its component has gone first. - `page_updated()`: In the browser: waits until the page shows what was just set, as in a handler before reading the page. - `js_has(name)`: In the browser: whether the page has `name`, without calling it; false on the server. - `cursor_index(s, n)`: The character a field's cursor at `n` is before, as `slice` counts. - `args()`: What followed `--` on the command line: `quillo run tool.qwe -- a b`. - `stdin()`: All that is piped to a script, as text: `cat a.csv | quillo run tool.qwe`. Not while the program serves. - `read_line()`: The next line a script is given, without its line break; null at the end. Not while the program serves. - `exit(n)`: Ends a script with status `n`, 0 to 255 (0 if left out), once what it printed is out. Not while the program serves. - `print(values)`: Writes the values as text, a space between, on stdout (the console in a page). - `str(x)`: `x` as text: a whole float as `2.0`, a list or map as Quillo writes it, null as `null`. - `int(x)`: A number cut toward zero, `true` as 1, or text of digits; `"1.0"` and a number too large for an int are error values. - `float(x)`: A number or numeric text as a float; anything else is an error value. - `dec(x)`: A decimal from text, an int, or a float through its shortest text; else an error value. - `format_number(x, locale, digits, mode)`: `x` as `locale` writes numbers, to `digits` if given: a tie away from zero, or as `mode` says (`"half_even"` as money). - `len(x)`: A string's characters, a list's items, a map's keys, an `html` value's bytes; null is 0. - `type_of(x)`: The name of `x`'s type: `int`, `str`, `list`, `map`, `null`, `error` and the like. ### Errors - `err(x)`: An error value holding `x`. - `is_err(x)`: Whether `x` is an error value. - `unwrap(x)`: `x`, or a runtime error if it is an error value. ### Numbers - `abs(x)`: The size of `x`, without its sign; a decimal stays a decimal. - `round(x, digits, mode)`: A float rounds half away from zero, to an int or `digits` places; a decimal half to even, or by `mode`. - `floor(x)`: `x` rounded down: an int from a float, a decimal from a decimal. - `ceil(x)`: `x` rounded up: an int from a float, a decimal from a decimal. - `sqrt(x)`: The square root, a float; `NaN` for a negative `x`, where `math.sqrt` is an error. - `pow(x, y)`: `x` to the power `y`: an int for ints (`y` >= 0, if it fits), a decimal for a decimal to an int's power, else a float. ### Randomness - `random()`: A float from 0 up to but not including 1; fast but predictable, so not for secrets. - `random_int(lo, hi)`: An int from `lo` to `hi`, both included; fast but predictable, so not for secrets. - `uuid()`: A random version 4 UUID, from the operating system: it can serve as a session id or token. ### Answers and escaping - `raw(x)`: `x` as `html`, shown as it is: only for text you trust. - `escape(x)`: `x` as text with `& < > " '` written as entities. - `url_encode(x)`: `x` percent-encoded; a map gives a query string, leaving out keys whose value is null. - `file(path, options)`: An answer serving the file, or a 404; `{ cache: "1y" }` lets browsers keep it that long. - `redirect(url, status)`: An answer sending the browser to `url`, with status 303 unless given. - `local_path(next)`: `next` if it is an address on this site as a browser reads it, else null: `redirect(local_path(next) ?? "/")`. - `respond(status, body, headers)`: An answer with this status and, if given, body and headers. ### The program and its files - `env(name, default)`: The environment variable `name` (a `.env` file counts), else `default` (null unless given). - `platform()`: A map of where the program runs: `os`, `device`, `arch`, `runtime` and more. On the server only. - `now()`: Milliseconds since 1970, an int. - `sleep(ms)`: Waits `ms` milliseconds while other requests run; a job or a tick ends here when the server stops. - `read_file(path)`: The file's text, with bytes that are not UTF-8 replaced; an error value if it cannot be read. - `write_file(path, v)`: Writes `v` as text, making folders and replacing the file; null, or an error value. - `delete_file(path)`: Removes a file, or a folder and what is in it; nothing there is no error. - `check_program(path, files)`: What `quillo check` says of a program, as maps; `files` gives text in place of what is on disk. - `run_script(source, vars)`: Runs users' code in a sandbox that sees `vars`; its last value, or an error value. - `allow_cross_site(path)`: Lets routes under `path` take form posts from other sites' pages, otherwise refused. - `site_headers(path, headers)`: At the top: headers for every answer (under `path`) that sets none of its own; null takes one of Quillo's away. - `ready(name, f)`: Adds a check to `/_quillo/ready`: `name` is ready while `f` gives `true`. - `style_with(cmd)`: Passes every component's and view's `style` through the command `cmd` as the program loads. - `schedule(when, f, options)`: Runs `f` at `when`: a duration (`"5m"`, on the clock) or a cron line, in UTC. - `parallel(fs)`: Calls the functions at once, or those of one list, and gives their results in order. ### Uploads - `save_upload(file, path)`: Writes a file from `request.files` to `path` in the program's folder; gives `path`, or an error value. - `read_upload(file)`: A file from `request.files` as text; an error value if it cannot be had. ### Cookies and sessions - `set_cookie(name, value, options)`: Adds `Set-Cookie` to the answer; `HttpOnly`, `SameSite=Lax`, `Path=/` and `Secure` by default. - `cookie(name)`: The request's cookie called `name`, or null; null outside a request too. - `delete_cookie(name, options)`: Removes a cookie; `options` gives the `path` and `domain` it was set with. - `session()`: The session as a map, `{}` when there is none. - `set_session(data, options)`: Replaces the session, for 30 days unless `max_age` says; null ends it. The browser can read it. - `end_session()`: Forgets the session and removes its cookie; a copy someone kept stays valid until it expires. ### Translations - `translations(dir, options)`: Loads `/.json`, or takes a map of locales; `{ default }` names the default. - `locale_from(f)`: Sets how a request's locale is found: `f` gets the request, and null means the usual way. - `locale()`: The current locale, or null without `translations`. - `with_locale(locale, f)`: Runs `f` in `locale` and gives its result (for an email in the recipient's language). - `t(key, vars)`: The text of `key` in the current locale, `{name}` filled from `vars`; `count` picks a plural form. ### Tenants - `tenant()`: The tenant the code runs for, or null. - `tenant_from(rule)`: Sets each request's tenant: the host's part before the domain `rule`, or what a function of it gives. - `new_tenant(name, f)`: Makes a tenant's database and runs `f` for it, or gives an error when that tenant exists, so a signup cannot land in a customer's data. - `with_tenant(name, f)`: Runs `f` for that tenant, with its database and live updates; a new tenant's database is made. ### Components - `url()`: `{ path, query, hash }` of the request, or of the address bar in the browser, where it is followed. - `navigate(path)`: Goes to `path` from a page's code; on the server it does nothing, and `redirect` is the way. - `every(ms, f, options)`: Calls `f` every `ms` milliseconds: on the server at a program's top, in the browser in a component. - `ask(message, options)`: Asks in a dialog on the page and waits for true or false; an error on the server. - `notify(message, options)`: Shows a note on the page that goes by itself; an error on the server. - `js(name, args)`: Calls a function of the page's scripts by its dotted `name`, written in the code; null on the server. - `js_new(name, args)`: Makes an object of a class of the page's scripts, by `name`; null on the server. - `defer(x)`: `x`; as the `state` initializer of a component placed in a page, the page goes first and `x` follows. ### Live data - `live(load, args)`: State that follows the server: runs the `server fn` `load`, and again when what it read changes; `{ every: "2s" }` before it sets a gap. - `waiting(state)`: Whether a `live` state waits for the answer to new arguments; false on the server. - `publish(topics)`: Wakes the pages whose `live` data watches these topics. - `watch(topics)`: Inside a `live` loader, runs it again when these topics are published. - `unwatched(f)`: Calls `f`; what it reads does not make the running `live` loader run again. ### Streaming - `stream(f, options)`: An answer sent as it is made: `f` gets `send`; text goes as it is, other values as lines of JSON. - `events(f, options)`: An answer of Server-Sent Events: `f` gets `send(value, name)`; `send(null)` keeps it open. - `listen(url, f)`: In a component's code, `f` gets what the stream at `url` sends; it opens again if the connection drops. - `receive(url, f, options)`: In a handler, sends the request and calls `f` with what the answer streams, until it ends. ### JSON - `json.parse(s)`: The value in JSON text; bad JSON is an error value. - `json.stringify(v, pretty)`: `v` as JSON, indented by two spaces when `pretty` is true; a decimal as a string. ### Regular expressions - `re.test(text, pattern, flags)`: Whether `pattern` matches anywhere in `text`; `flags` are `i`, `m` and `s`. - `re.find(text, pattern, flags)`: The first match as `{ text, start, end, groups, named }`, or null. - `re.find_all(text, pattern, flags)`: Every match, from left to right, as `re.find` gives one. - `re.replace(text, pattern, with, flags)`: Every match replaced by `with`: text with `$1`, `$`, `$0` and `$$`, or a function of the match. - `re.split(text, pattern, flags)`: The text between the matches, as a list. ### SQL text - `css(text)`: The text as written; as a tag, it tells editors to highlight it as CSS. - `sql(text)`: The text as written; as a tag, it tells editors to highlight it as SQL. - `sql_name(name)`: A table's or column's name, checked and quoted; a list gives them comma-separated. - `sql_param(name)`: A named parameter, `:name`, checked; a list gives them comma-separated. ### Database - `db.open(target, options)`: Opens the program's database: a SQLite path or a server URL. A failure is an error value, not a stop. - `db.connect(target, options)`: Opens another database and gives its `exec`, `query`, `one` and the like; one `target`, one connection. - `db.system(target)`: Keeps Quillo's own tables (jobs, calls made later, `db.atomic`'s decisions) in this database. - `later.status(id)`: What became of a call made later: `{ state, tries, error }` while waiting or failed, `{ state: "done", result }`, or null. - `db.shards(targets)`: Databases split by a key: `.on(key)` is a shard's connection, `.all(sql)` asks every shard. - `db.atomic(dbs, f)`: Runs `f` as one transaction over the databases listed: all of it commits, or none. - `db.exec(sql, params)`: Runs SQL, with `?` or `:name` values; `{ changes, last_id }`, or an error value. - `db.exec_many(sql, rows)`: Runs SQL once for each row (a list of its `?` values), all or none; `{ changes }`, or an error value. - `db.query(sql, params)`: Every row as a list of maps, all in memory, or an error value. - `db.one(sql, params)`: The first row as a map, or null, or an error value. - `db.transaction(options, f)`: Runs `f` all or nothing; an error value rolls it back. `options` may be left out. - `db.sql_name(name)`: A name quoted for this database: on a connection (`shop.sql_name(col)`), for that one, as MySQL reads "x" as text. - `db.error_kind(e)`: What failed: `unique`, `foreign_key`, `not_null`, `check` or `conflict`, else null. - `db.migrate(dir)`: Runs the `.sql` files of `dir` (`migrations` unless given) not yet run, in name order; gives their names. - `db.tenants()`: The names of the tenants that have a database; it needs a `{tenant}` target, not a function. - `db.tenant_exists(name)`: Whether tenant `name` has a database, without making one; it needs a database per tenant. - `idempotent(options, f)`: Runs `f` once per `Idempotency-Key`: the key again gets the first answer. `options` may be left out. ### HTTP client - `http.get(url, headers, options)`: `{ status, ok, headers, body, json }` for any status; failing to connect is an error value. - `http.delete(url, headers, options)`: Sends a DELETE; the answer is as `http.get` gives it. - `http.post(url, body, headers, options)`: Sends `body`: text as it is, maps and lists as JSON. The answer is as `http.get` gives it. - `http.put(url, body, headers, options)`: Sends a PUT, its `body` as `http.post` does; the answer is as `http.get` gives it. - `http.patch(url, body, headers, options)`: Sends a PATCH, its `body` as `http.post` does; the answer is as `http.get` gives it. - `http.request(method, url, body, headers, options)`: Sends a request of any method, its `body` as `http.post` does. - `http.stream(url, f, options)`: Reads an answer as it arrives: `f` gets each event, line or piece, and stops it by returning `false`. ### Images - `image.info(path)`: `{ width, height, format, alpha }` from the file's header, or an error value. - `image.convert(src, dest, options)`: Writes `dest` from `src`, as `{ crop, width, format, quality }` say; JPEG unless told, never enlarged. ### Crypto - `crypto.sha256(text)`: The SHA-256 of `text`, in hex. - `crypto.hmac(key, text)`: The HMAC-SHA256 of `text` with `key`, in hex. - `crypto.token(bytes)`: Random text, base64url, from 1 to 1,024 random bytes; 32 bytes (43 characters) by default. - `crypto.hash_password(pw)`: A salted Argon2id hash of `pw`, to store. - `crypto.verify_password(pw, hash)`: Whether `pw` is the password of `hash`; false for anything that is not such a hash. - `crypto.equal(a, b)`: Whether two strings are equal, in constant time, for comparing secrets. ### UDP - `udp.listen(port, f, options)`: At the top of a program, `f` gets each packet that comes to `port`; `{ host, queue }`. - `udp.send(host, port, data, options)`: Sends one packet: text, a list of byte values, or a value as JSON. Null, or an error value. - `udp.reply(packet, data)`: Sends `data` back to where `packet` came from, from the port it came to. ### Channels - `channel.on(name, f, options)`: At the top, `f(msg, peer)` gets pages' messages; `{ join, leave, tenants }`, a room per tenant. - `channel.send(name, peer, value, options)`: Sends `value` to one page, by peer or id, and gives whether it was there. - `channel.broadcast(name, value, options)`: Sends `value` to every page in the channel, and gives how many took it; `{ except, reliable }`. - `channel.peers(name)`: The ids of the pages in the channel. - `channel.open(name, f, options)`: In a component, `f` gets what the server sends on the channel; the result's `.send(value)` sends. ### Media - `media.rtp(name, options)`: Makes a stream from RTP on `{ video, audio, host }`: H.264 and Opus, each on a port of its own. - `media.close(name)`: Ends a stream and lets its ports go; true if there was such a stream. - `media.on(name, options)`: Who may send stream `name` (`*`: each it starts) and watch it: `{ publish, watch, tenants }`. - `media.streams()`: The streams, in order of name, as `{ name, viewers, video, audio }`. ### Dates - `date.today(tz)`: Today's date as `YYYY-MM-DD`, in the zone `tz`: UTC unless given. - `date.now(tz)`: The date-time now, to the second, at the zone's offset: UTC unless given. - `date.parse(s, pattern)`: A date or date-time from text, read as ISO or by `pattern`; an error value if it is not one. - `date.valid_zone(z)`: Whether `z` is a time zone: a name, an offset, or `UTC`. - `re.valid(pattern, flags)`: Whether `pattern` is a pattern Quillo can run. - `date.valid(s, kind)`: Whether `s` is a date or a date-time; `kind` is `"date"` or `"date-time"` for only that. - `date.of(y, m, d)`: The date with this year, month and day; no such date is an error. - `date.parts(d)`: `{ year, month, day, weekday }`, and `hour`, `minute`, `second`, `offset` for a date-time. - `date.weekday(d)`: The weekday of `d`: 1 for Monday to 7 for Sunday. - `date.is_leap_year(year)`: Whether `year`, an int or a date, is a leap year. - `date.days_in_month(year, month)`: How many days the month has; a date in place of `year` needs no `month`. - `date.add_days(d, n)`: The date `n` days after `d`; a date-time is an error (`date.date_in` gives its date). - `date.add_months(d, n)`: The date `n` months after `d`, kept within the month: `2026-01-31` plus 1 is `2026-02-28`. - `date.add_years(d, n)`: The date `n` years after `d`: `2024-02-29` plus 1 is `2025-02-28`. - `date.days_between(a, b)`: `b - a`, in days; both are dates, not date-times. - `date.months_between(a, b)`: Whole months from `a` to `b`: `2026-01-31` to `2026-02-28` is one. - `date.start_of_month(d)`: The first day of the month of `d`. - `date.end_of_month(d)`: The last day of the month of `d`. - `date.to_zone(t, tz)`: The date-time `t` at the zone's offset then, daylight saving included; UTC unless given. A zero fraction is dropped. - `date.date_in(t, tz)`: The calendar date of the date-time `t` in the zone; UTC unless given. - `date.at(d, time, tz, options)`: The date-time of a local `HH:MM` on `d` in the zone (or one text, `d` as "2026-10-27T14:30"); `{ repeated, skipped }`. - `date.compare(a, b)`: -1, 0 or 1 by the instants `a` and `b` name, a fraction of a second included: the safe way to order date-times written differently. - `date.format(d, pattern)`: `d` as text by a pattern (`DD/MM/YYYY`), or `{ locale, style }`, or `{ locale, pattern }`. - `date.ms(t)`: `t` as milliseconds since 1970, as `now()` gives; a date is its midnight in UTC. - `date.from_ms(ms, tz)`: Milliseconds since 1970 as a date-time, to the second, at the zone's offset; UTC unless given. ### Money - `money.of(amount, currency, mode)`: Money from a dec, int or text; too many decimals are an error value unless `mode` rounds. - `money.from_minor(minor, currency)`: Money from minor units: `money.from_minor(1250, "USD")` is 12.50. - `money.to_minor(m)`: The amount in minor units (cents), an int. - `money.add(a, b)`: The sum of two amounts of one currency; two currencies are an error. - `money.sub(a, b)`: `a` less `b`, of one currency; two currencies are an error. - `money.mul(m, factor, mode)`: `m` times a dec or an int, rounded to the currency, half to even unless `mode` says. - `money.neg(m)`: The amount with its sign turned. - `money.compare(a, b)`: -1, 0 or 1, for two amounts of one currency. - `money.zero(currency)`: Zero of the currency; an unknown currency is an error value. - `money.is_zero(m)`: Whether the amount is zero. - `money.allocate(m, ratios)`: `m` split by a list of ratios, or into `ratios` equal parts, the shares adding up exactly. - `money.round(m, mode)`: An amount rounded to the currency's decimals, half to even unless `mode` says. - `money.minor_units(currency)`: How many decimals the currency has (JPY 0, USD 2); an unknown one is an error value. - `money.parse(text, currency, locale, mode)`: An amount as `locale` writes it, for a form: `"1.234,50 €"` in de-DE is 1234.50 euros; bad text is an error value. - `money.format(m, locale)`: The amount as `locale` writes it: `$1,234.50`; else the program's locale, or en-US. ### math - `math.sqrt(x)`: The square root; a negative `x` is an error, where `sqrt` gives `NaN`. - `math.cbrt(x)`: The cube root. - `math.exp(x)`: `e` to the power `x`; too large a result is an error. - `math.exp2(x)`: 2 to the power `x`; too large a result is an error. - `math.expm1(x)`: `e` to the power `x`, less 1, accurate for `x` near 0. - `math.log(x, base)`: The natural log of `x`, or its log in `base`; `x` of 0 or less is an error. - `math.log2(x)`: The log in base 2; `x` of 0 or less is an error. - `math.log10(x)`: The log in base 10; `x` of 0 or less is an error. - `math.log1p(x)`: The natural log of `1 + x`, accurate for `x` near 0; `x` of -1 or less is an error. - `math.pow(x, y)`: `x` to the power `y`, always a float; 0 to a negative power is an error. - `math.sin(x)`: The sine of `x` radians. - `math.cos(x)`: The cosine of `x` radians. - `math.tan(x)`: The tangent of `x` radians. - `math.asin(x)`: The angle in radians whose sine is `x`; outside -1 to 1 is an error. - `math.acos(x)`: The angle in radians whose cosine is `x`; outside -1 to 1 is an error. - `math.atan(x)`: The angle in radians whose tangent is `x`. - `math.atan2(y, x)`: The angle in radians of the point (`x`, `y`), with `y` written first. - `math.sinh(x)`: The hyperbolic sine of `x`. - `math.cosh(x)`: The hyperbolic cosine of `x`. - `math.tanh(x)`: The hyperbolic tangent of `x`. - `math.asinh(x)`: The inverse hyperbolic sine of `x`. - `math.acosh(x)`: The inverse hyperbolic cosine of `x`; below 1 is an error. - `math.atanh(x)`: The inverse hyperbolic tangent of `x`; -1, 1 and beyond are an error. - `math.degrees(x)`: `x` radians in degrees. - `math.radians(x)`: `x` degrees in radians. - `math.hypot(coords)`: The distance from the origin to the point with these coordinates. - `math.dist(p, q)`: The distance between two points, lists of the same length. - `math.floor(x)`: The greatest int not above `x`; an infinity or `NaN` is an error. - `math.ceil(x)`: The least int not below `x`; an infinity or `NaN` is an error. - `math.trunc(x)`: `x` cut toward zero, an int; an infinity or `NaN` is an error. - `math.fabs(x)`: The size of `x`, a float. - `math.copysign(x, y)`: The size of `x` with the sign of `y`. - `math.fmod(x, y)`: The remainder of `x / y`, with the sign of `x`; `y` of 0 is an error. - `math.remainder(x, y)`: `x` less the multiple of `y` nearest to it, as IEEE 754 says; `y` of 0 is an error. - `math.modf(x)`: `[fraction, whole part]`, both floats with the sign of `x`. - `math.frexp(x)`: `[m, e]` with `x = m * 2^e`, `m` at least 0.5 in size and below 1. - `math.ldexp(x, e)`: `x * 2^e`. - `math.factorial(n)`: `n!`, an int; past 20 it no longer fits, which is an error. - `math.gcd(ns)`: The greatest common divisor of the ints given, or of one list of them. - `math.lcm(ns)`: The least common multiple of the ints given, or of one list of them. - `bit.and(a, b)`: The bits set in both ints. - `bit.or(a, b)`: The bits set in either int. - `bit.xor(a, b)`: The bits set in one int but not both. - `bit.not(a)`: `a` with its 64 bits flipped: `bit.not(0)` is `-1`. - `bit.shl(a, n)`: `a` shifted left by 0 to 63 bits; bits past the top are dropped, not an overflow. - `bit.shr(a, n)`: `a` shifted right by 0 to 63 bits, keeping its sign. - `math.comb(n, k)`: How many ways to choose `k` of `n`, order aside; 0 when `k` is more than `n`. - `math.perm(n, k)`: How many ways to arrange `k` of `n`; `k` is `n` unless given, and 0 when more than `n`. - `math.isqrt(n)`: The square root of `n`, rounded down to an int. - `math.isclose(a, b, rel_tol, abs_tol)`: Whether `a` and `b` are nearly equal; `rel_tol` is 1e-9 and `abs_tol` 0 unless given. - `math.isfinite(x)`: Whether `x` is neither an infinity nor `NaN`. - `math.isinf(x)`: Whether `x` is an infinity. - `math.isnan(x)`: Whether `x` is `NaN`. - `math.prod(xs, start)`: The items multiplied, times `start` (1 unless given); an int while everything is one. - `math.fsum(xs)`: The sum of `xs` as a float, exactly rounded; an error if it passes the floats on the way, or for `inf` with `-inf`. - `math.sumprod(a, b)`: The sum of the products of two lists of one length; ints stay exact. - `math.erf(x)`: The error function of `x`. - `math.erfc(x)`: `1 - erf(x)`, accurate for large `x`. - `math.gamma(x)`: The gamma function of `x`; 0 and negative ints are an error. - `math.lgamma(x)`: The natural log of the size of the gamma function; 0 and negative ints are an error. ### stats - `stats.mean(data)`: The average, a float; no data is an error. - `stats.fmean(data, weights)`: The average, weighted by `weights` if given; no data is an error. - `stats.geometric_mean(data)`: The geometric mean; every number must be above 0. - `stats.harmonic_mean(data)`: The harmonic mean; a negative number is an error, and a zero makes it 0. - `stats.median(data)`: The middle value, or the mean of the two middle ones; no data is an error. - `stats.median_low(data)`: The middle value, or the lower of the two middle ones. - `stats.median_high(data)`: The middle value, or the higher of the two middle ones. - `stats.mode(data)`: The most common value, the first seen on a tie; any values, text too. No data is an error. - `stats.multimode(data)`: Every most common value, in the order first seen; any values, and `[]` for no data. - `stats.pvariance(data, mean)`: The population variance; give `mean` if it is known. - `stats.variance(data, mean)`: The sample variance, of two values at least; give `mean` if it is known. - `stats.pstdev(data, mean)`: The population standard deviation; give `mean` if it is known. - `stats.stdev(data, mean)`: The sample standard deviation, of two values at least; give `mean` if it is known. - `stats.quantiles(data, n, method)`: The `n - 1` cut points, `n` being 4 unless given; `method` is `"exclusive"` or `"inclusive"`. - `stats.percentile(data, p)`: The value at `p`, from 0 to 100, or a list for a list of them, by numpy's linear rule. - `stats.covariance(x, y)`: The sample covariance of two lists of one length, two values at least. - `stats.correlation(x, y, method)`: Pearson's correlation, or Spearman's with `"ranked"`; a constant list is an error. - `stats.linear_regression(x, y, proportional)`: `{ slope, intercept }` of the best line; `proportional` makes it pass through 0. - `stats.describe(data)`: `{ count, sum, mean, std, min, q1, median, q3, max }`; no data gives zeros and nulls, no error. - `stats.histogram(data, bins)`: `{ counts, edges }`: `bins` equal bins, 10 unless given, or the edges as a list. - `stats.zscore(data)`: How many population deviations each value is from the mean; a constant list gives zeros. - `stats.normalize(data)`: The values scaled to 0..1; a constant list gives zeros. - `stats.rank(data)`: Each value's rank from 1; ties share their average rank, a float. - `stats.normal_pdf(x, mu, sigma)`: The normal distribution's density at `x`; `mu` is 0 and `sigma` 1 unless given. - `stats.normal_cdf(x, mu, sigma)`: The share of the normal distribution below `x`; `mu` is 0 and `sigma` 1 unless given. - `stats.normal_inv(p, mu, sigma)`: The `x` with the share `p` of the distribution below it; `p` is between 0 and 1, neither included. ### vec - `vec.add(a, b)`: Item by item: two lists of one length, or a list and a number; ints stay ints. - `vec.sub(a, b)`: Item by item: two lists of one length, or a list and a number; ints stay ints. - `vec.mul(a, b)`: Item by item: two lists of one length, or a list and a number; ints stay ints. - `vec.div(a, b)`: Item by item: two lists of one length, or a list and a number; ints that divide exactly stay ints. - `vec.mod(a, b)`: The remainder item by item, with the sign of `a`: two lists of one length, or a list and a number. - `vec.pow(xs, p)`: Each item to the power `p`, as floats. - `vec.dot(a, b)`: The dot product of two lists of one length; ints stay exact. - `vec.norm(xs, p)`: The length of `xs` as a vector: the p-norm, `p` being 2 unless given. - `vec.cumsum(xs)`: The running total of the items. - `vec.cumprod(xs)`: The running product of the items. - `vec.diff(xs)`: Each item less the one before it: one shorter than `xs`. - `vec.argmin(xs)`: The position of the least item, or null for an empty list; `NaN` is passed over. - `vec.argmax(xs)`: The position of the greatest item, or null for an empty list; `NaN` is passed over. - `vec.argsort(xs, descending)`: The positions that would sort `xs`, equal items in their order; greatest first with `descending`. - `vec.clip(xs, lo, hi)`: Each item kept within `lo` and `hi`; either may be null. - `vec.abs(xs)`: The size of each item; ints stay ints. - `vec.sqrt(xs)`: The square root of each item; a negative item gives `NaN`, not an error. - `vec.exp(xs)`: `e` to the power of each item. - `vec.log(xs)`: The natural log of each item; a negative item gives `NaN`, not an error. - `vec.round(xs, digits)`: Each item rounded, halves away from zero: to ints, or to `digits` places as floats. - `vec.linspace(start, stop, n, endpoint)`: `n` evenly spaced numbers (50 unless given), `stop` included unless `endpoint` is false. - `vec.arange(start, stop, step)`: From `start` by `step`, up to but not including `stop`; given one number, from 0 up to it. - `vec.zeros(n)`: A list of `n` zeros, at most ten million. - `vec.ones(n)`: A list of `n` ones, at most ten million. - `vec.full(n, x)`: A list of `n` copies of `x`, at most ten million. - `vec.rolling_mean(xs, window)`: The mean of each run of `window` neighbours: one per full window, none if the list is shorter. - `vec.rolling_sum(xs, window)`: The sum of each run of `window` neighbours: one per full window, none if the list is shorter. - `vec.matmul(a, b)`: Rows `a` times rows `b`, or times a list of numbers, which gives a list. - `vec.transpose(rows)`: Rows turned into columns; all rows must have one length. - `vec.column(rows, key)`: The field `key` of each map, or the item `key` of each list; null where a row has none. ## More - [The whole manual in one file](https://quillolang.org/v0.7.0/llms-full.txt) - [Documentation](https://quillolang.org/docs/) - [Plugins](https://quillolang.org/plugins/) - [A program to start from](https://github.com/quillolang/starter)