Skip to main content

Libraries

Libraries are the functions a document can call that aren't part of the document itself: printing, string and list helpers, time, encryption, and so on. They're grouped by name, and you call them with that name: Time::now(), Num::abs(-2).

Calling Library Functions​

There are three ways to call a library function, and they're all the same call:

calling.stofPlayground ↗
#[main]
fn main() {
  const name = 'stof';

  pln(Str::upper(name));    // the library, then the function
  pln(name.upper());        // as a method: the value's type picks the library (Str)
  pln(Str.upper(name));     // a dot works too, unless a field or variable is named Str
}
Output

These docs use Lib::func() for calling a library directly, and the method form on values. :: always means the library, so it can't be confused with a field or variable of the same name, and it reads as a library call at a glance. The method form works for every type library: a string's methods come from Str, a list's from List, an object's from Obj, and so on. Std functions don't need a name at all, so pln(..) is Std::pln(..).

Lib?::func() returns null instead of throwing when the library or function doesn't exist, which is handy for optional host libraries:

optional.stofPlayground ↗
#[main]
fn main() {
  const sent = App?::notify('hello');   // null: this host has no App library
  pln(sent ?? 'no App library here');
}
Output

What's Built In​

LibraryWhat it's forAvailable in
StdPrinting, assertions, parsing and exporting, collections, introspectionEverywhere
Str, Num, List, Map, Set, TupMethods on strings, numbers, and collectionsEverywhere
Obj, Fn, DataWorking with objects, functions, and data in the document graphEverywhere
Blob, Ver, PromptBytes, semantic versions, and prompt trees for AI contextsEverywhere
TimeTimestamps, durations, and datesEverywhere
MdMarkdown to HTML or JSONEverywhere
AgeEncrypting parts of a documentEverywhere
HttpNetwork requestsWhen the host turns it on: JavaScript, Python, Rust (http feature), CLI
fsReading and writing filesWhen the host turns it on: Python, Rust, CLI
ImageLoading, editing, and exporting imagesPython, Rust (image feature), CLI
PdfText and images from PDFsPython, Rust (pdf feature), CLI

"Everywhere" means the JavaScript package (Node.js and browsers), Python, Rust, and the stof CLI. The runnable examples on this site use the JavaScript package.

What a Document Can Reach​

A document can always read and change itself and call the libraries above that are marked "Everywhere". Nothing on the outside, though: the file system, environment variables, importing files from disk, and the network are all off until the host turns them on:

AccessJavaScriptPythonRust
Network (Http)doc.allowHttp(['api.example.com'])doc.allow_http_hosts([...])graph.allow_http_hosts([...])
Network, any hostdoc.allowHttp()doc.allow_http()graph.allow_http()
Files, environment, file importsnot availabledoc.allow_system()graph.allow_system()

The stof CLI turns everything on, since it runs your own files. Each call also has a time limit, 2 minutes by default, which the host can change: doc.setMaxExecutionTime(ms) (JavaScript), doc.set_max_execution_time(seconds) (Python), graph.max_execution_time (Rust).

Adding Your Own​

The host can add its own library functions, and that's the usual way to give a document access to something specific: your database, your notification service, your app's state. A document can call those and nothing else it wasn't given.

import { StofDoc } from '@formata/stof';

const doc = await StofDoc.new(`
#[main]
fn main() {
App::notify('order shipped');
}
`);
doc.lib('App', 'notify', (message: string) => console.log('notify:', message));
await doc.run();
from pystof import Doc

doc = Doc()
doc.lib('App', 'notify', lambda message: print('notify:', message))

In Rust, a library function is a LibFunc inserted with graph.insert_libfunc(..).