Skip to main content

Import & Export

Stof can read and write any format it has an implementation for — JSON, YAML, TOML, and Stof itself out of the box, with richer formats like PDF or images available as libraries. Two of the mechanisms below run entirely inside a document and work fine in this browser sandbox; the file-based import statement needs a real filesystem, so those examples further down are reference material, not runnable.

Exporting: stringify and blobify

stringify(format, target) exports to a string; blobify(format, target) does the same as raw bytes — every format that supports stringify supports blobify, but it's up to the format implementation whether to support the other way around:

export.stof
#[main]
fn main() {
  const object = new {
      a: "hello",
      b: 42,
      c: true,
  };

  const json: str = stringify("json", object);
  const bytes: blob = blobify("json", object);

  pln(json);
  pln(bytes as str);
}
Output

Parsing at Runtime

parse(source, location, format) is the runtime counterpart to the import statement below — and because it just takes a string, it works fine sandboxed. This is the same self-modification idea from How Stof Works, made concrete: a document handing itself new logic while it runs.

self-parse.stof
#[main]
fn main() {
  const stof = r#"
      fn my_function() {
          pln("Isn't this cool!");
      }
  "#;
  parse(stof, self, format = "stof");

  self.my_function();
}
Output

Worth being precise about what's actually sandboxed here: parse can add fields and functions to the document, but it can't reach outside it — no filesystem, no network, unless the host explicitly hands the document a library that provides one. A string full of Stof arriving from an untrusted source is safe to parse and run for exactly that reason.

The import Statement

import <optional format> "path.extension" as <optional location>

The plain form, import "file", assumes a .stof extension and parses into the current context (self):

Object: {
import "./docs.md";

// Object.md now holds the string contents of docs.md
fn markdown() -> str { self.md }
}

Relative Paths & Format Selection

Paths are relative to wherever the CLI or host was invoked from, though a leading ./ lets nested imports navigate correctly as they parse. The format is inferred from the file extension unless you specify one explicitly:

// format inferred from extension:
import "report.pdf";

// format forced explicitly — reads file.stof as plain text,
// not as Stof source:
import text "file.stof";

Import Location (as)

Without as, an import lands on the calling object. as lets you redirect it — but the path after as is always absolute, so it's easy to accidentally create a new root instead of a child of self:

// creates self.Object if needed:
import "./docs.md" as self.Object;

// creates a NEW DOCUMENT ROOT called Object — not the same thing:
import text "./docs.md" as Object;

Packages: the @ Shortcut

Each @ in an import path expands to stof/ — a lightweight convention for package-style imports, paired with the pkg format for importing a whole directory via its pkg.stof manifest:

import "@formata";
// equivalent to:
import "stof/formata.stof";

// pkg format reads an "import" field from stof/formata/pkg.stof
// and pulls in whatever paths it lists:
import pkg "@formata";