JavaScript API
Custom pipes run synchronously in an ES2020 JavaScript runtime. Their TypeScript entry point is bundled before execution.
export function transform(this: tCtx, input: Buffer): string | Buffer | TransformResult
export function index(this: iCtx, input: Buffer): unknown
The generated declarations are in .falz/types/.
Transform context: tCtx
| Property | Type | Meaning |
|---|---|---|
file |
FileInfo |
Source file metadata. |
globals |
Record<string, unknown> |
Project variables, after environment expansion. |
vars |
Record<string, string> |
<Var> values from the matching <Content>. |
entry |
{ type: string, tag: string } |
type is content or asset; tag is the content/asset name. |
kv |
KV |
Read-only cross-entry index data. |
blob |
Blob |
This entry's own cached index() return value. |
Fragment context: fCtx
Fragment transforms receive the following context:
| Property | Type | Meaning |
|---|---|---|
name |
string |
The <Fragment name="..."> value. |
file |
FileInfo (optional) |
Source metadata when src exists; paths are relative to the scheme root. |
globals |
Record<string, unknown> |
Project variables, after environment expansion, as in normal pipes. |
vars |
Record<string, string> |
Content <Var> values used to compile the layout. |
entry |
{ type: "fragment", tag: string } |
Fragment type and declared name (tag equals name). |
debug |
Debug |
start() starts a timer; end(message) logs the elapsed duration at debug level. |
A source-less fragment has no file and receives an empty input buffer. Content variables remain available as top-level properties for compatibility (for example, this.lang), but cannot overwrite context fields. All values, including colliding names, remain accessible through this.vars.
Fragments are rendered per layout context, not per page: they do not receive a current page or output URL. Fragment indexing and KV access are not supported.
export function transform(this: fCtx): string {
switch (this.name) {
case 'nav': return renderNav(this.vars.lang)
case 'footer': return renderFooter(this.vars.lang)
default: throw new Error(`Unknown fragment: ${this.name}`)
}
}
Declare <Fragment name="nav" pipe="shell"/> without a dummy source file. See Layout reference.
FileInfo
For content/posts/hello.md:
| Property | Example | Meaning |
|---|---|---|
path |
content/posts/hello.md |
Slash-normalized path relative to project root. |
dir |
content/posts |
Parent directory. |
name |
hello.md |
Filename with extension. |
stem |
hello |
Filename without final extension. |
ext |
md |
Extension without dot. |
baseDir |
content/posts |
Directory from which this entry is scoped by its layout. |
TransformResult
interface TransformResult {
content: string | Buffer
alias?: string
vars?: Record<string, string>
}
Fields:
content— transformed output inserted into the matching content slot;alias— optional value for{ALIAS}in the output path;vars— optional string values added to the layout variables. Keys identify layout placeholders and variables in expressions.
Returning another JavaScript value converts it to a string, but relying on that is less clear. Returning null or undefined is an error. An object must contain a string or Buffer content field.
Index context: iCtx
iCtx has file, globals, vars, and entry, with the same meanings as above. It also has kv: IndexKV, the write-only collector used to publish cross-entry values during indexing.
The return value of index() must be JSON-serializable. Falz stores it as this entry's blob, making it available later through this.blob.get() in transform(). See Index phase.
Index data
IndexKV
set(key: string, value: unknown): void— store a JSON-serializable value duringindex().keymust have the formnamespace:key, and the namespace must be incontract.provides.
KV
get(key: string): unknown— return a decoded value, ornullwhen missing.keys(prefix: string): string[]— return matching full keys in sorted order.
Only namespaces declared in the pipe's contract.consumes are loaded for its transforms.
Blob
get(): unknown— lazily decode this entry's ownindex()result, or returnnullif none exists.
Repeated calls in one transform return the same decoded value.
Built-in modules
Use ESM imports:
import { text, json } from "fs"
import { get } from "http"
import { toHtml } from "md"
Falz externalizes these names during bundling and provides them at runtime.
fs
The fs module is read-only and rooted at the project source tree. It cannot read the scheme tree, output tree, or arbitrary host paths.
| Method | Result | Behavior |
|---|---|---|
bytes(path) |
Uint8Array | undefined |
Read bytes; missing files return undefined. |
text(path) |
string | undefined |
Read UTF-8 text; missing files return undefined. |
json(path) |
any | undefined |
Read and parse JSON; malformed JSON throws. |
exists(path) |
boolean |
Test whether any filesystem entry exists. |
isFile(path) |
boolean |
Test for a regular file. |
isDirectory(path) |
boolean |
Test for a directory. |
size(path) |
number | undefined |
File size in bytes. |
lastModified(path) |
Date | undefined |
Last modification time. |
list(path) |
FileEntry[] |
Direct children only. Throws if path is not a directory. |
walk(path) |
FileEntry[] |
Recursive flat list in lexical order. Symlinks are not followed. |
FileEntry has name, /-prefixed slash-normalized path, size, modTime, isFile, isDirectory, and isSymlink. Directories report size 0.
Example:
import { json, walk } from "fs"
const settings = json("data/settings.json") ?? {}
const images = walk("images").filter(entry => entry.isFile)
Reads through fs are available to the pipe, but they are not automatically represented as individual layout dependencies. If output freshness depends on another file, arrange your workflow so a relevant entry changes or use an indexed namespace to fan out invalidation.
http
The HTTP API is synchronous. Configure an allowlist in the pipe's config.yaml; no hosts are allowed by default.
| Method | Signature |
|---|---|
get |
get(url, headers?): Response |
post |
post(url, body?, headers?): Response |
put |
put(url, body?, headers?): Response |
patch |
patch(url, body?, headers?): Response |
del |
del(url, body?, headers?): Response |
head |
head(url, headers?): Response |
url may be a string or URL. Headers may be a Headers object, a string-valued object, or [name, value][].
Body encoding:
- string:
text/plain;charset=UTF-8; Buffer,Uint8Array, orArrayBuffer:application/octet-stream;- object or array: JSON with
application/json;charset=UTF-8.
Set Content-Type explicitly in headers to override inference.
All methods throw for non-2xx responses. The error has status and response properties:
import { get, type Response } from "http"
try {
const value = get("https://api.example.com/item").json()
} catch (error) {
const e = error as Error & { status: number, response: Response }
console.error(e.status, e.response.text())
}
Response
Properties:
status: number— status code;statusText: string— standard status text;ok: boolean— true for 2xx;redirected: boolean— whether the final URL differs;url: string— final URL;headers: Headers— response headers.
Methods:
text(): string— decode body bytes as text;json(): any— parse JSON; throws for empty or malformed bodies;bytes(): Buffer— return aBuffer;arrayBuffer(): ArrayBuffer— return anArrayBuffer.
The body is buffered, so these accessors may be called more than once.
Headers
Construct with new Headers(), another Headers, a plain object, or pairs.
append(name, value)— add another value;delete(name)— remove all values for the name;get(name)— comma-join values, or returnnull;has(name)— test whether the name exists;set(name, value)— replace existing values;entries()— iterator of[name, value]pairs;keys()— iterator of names;values()— iterator of values;forEach(callback, thisArg?)— visit(value, name, headers);getSetCookie()— return separateSet-Cookievalues.
md
toHtml(markdown, options?)
Converts a string or Buffer to an HTML string.
import { commonOptions, toHtml } from "md"
return toHtml(input, commonOptions)
With no options, no optional parser/renderer flags are enabled. commonOptions enables common parsing features and smart punctuation.
options.parser boolean flags:
| Flag | Effect |
|---|---|
NoIntraEmphasis |
Ignore emphasis markers inside words. |
Tables |
Parse tables. |
FencedCode |
Parse fenced code blocks. |
Autolink |
Link bare URLs. |
Strikethrough |
Parse ~~text~~. |
LaxHTMLBlocks |
Loosen HTML block parsing. |
SpaceHeadings |
Require spaces in prefix headings. |
HardLineBreak |
Turn newlines into line breaks. |
NonBlockingSpace |
Convert backspace spaces to non-breaking spaces. |
TabSizeEight |
Expand tabs to eight spaces instead of four. |
Footnotes |
Parse Pandoc-style footnotes. |
NoEmptyLineBeforeBlock |
Allow blocks without a preceding empty line. |
HeadingIDs |
Parse explicit heading IDs. |
Titleblock |
Parse Pandoc title blocks. |
AutoHeadingIDs |
Generate heading IDs from text. |
BackslashLineBreak |
Parse trailing backslashes as line breaks. |
DefinitionLists |
Parse definition lists. |
MathJax |
Parse MathJax notation. |
OrderedListStart |
Preserve the first ordered-list number. |
Attributes |
Parse block attributes. |
SuperSubscript |
Parse super/subscript notation. |
EmptyLinesBreakList |
Let two empty lines end a list. |
Includes |
Enable include syntax. |
Mmark |
Enable Mmark syntax. |
options.renderer boolean flags:
| Flag | Effect |
|---|---|
SkipHTML, SkipImages, SkipLinks |
Omit that kind of output. |
Safelink |
Allow only trusted link protocols. |
NofollowLinks, NoreferrerLinks, NoopenerLinks |
Add the corresponding link relation. |
HrefTargetBlank |
Add target="_blank". |
CompletePage |
Emit a complete HTML page. |
UseXHTML |
Emit XHTML-style output. |
FootnoteReturnLinks |
Add links back from footnotes. |
FootnoteNoHRTag |
Omit the horizontal rule before footnotes. |
Smartypants |
Enable smart punctuation. |
SmartypantsFractions, SmartypantsDashes, SmartypantsLatexDashes, SmartypantsAngledQuotes, SmartypantsQuotesNBSP |
Tune smart punctuation. |
TOC |
Generate a table of contents. |
LazyLoadImages |
Add loading="lazy" to images. |
Unknown option keys are ignored.
tpl
render(template, variables)
Renders a string or Buffer with Plush and returns a string:
import { render } from "tpl"
return render("Hello <%= name %>", { name: "Ada" })
<%= expression %> emits escaped output; <% statement %> executes control flow without output. Syntax and missing-variable errors throw.
fasttpl
compile(template, params, config?)
Replaces tagged placeholders and returns a string:
import { compile } from "fasttpl"
compile("Hello {{name}}", { name: "Ada" })
Values may be strings or zero-argument functions returning strings. Unknown tags remain unchanged. config.startTag and config.endTag change delimiters; defaults are {{ and }}.
yaml
parse(src: string | Buffer): any— parse one YAML document; malformed YAML throws.stringify(value, options?): string— serialize a value and include a trailing newline.options.indentis a positive number and defaults to2. Function-valued and symbol-keyed properties are omitted.
Globals
console
console.log(...data)andconsole.info(...data)— info log;console.warn(...data)— warning;console.error(...data)— error;console.dump(...data)— pretty-print JSON-like values at info level.
Buffer
A Node-compatible Buffer subset is global. Common static methods are:
Buffer.from(string | array | ArrayBuffer, encoding?);Buffer.alloc(size, fill?, encoding?);Buffer.concat(buffers, totalLength?);Buffer.isBuffer(value)andBuffer.isEncoding(name);Buffer.byteLength(value, encoding?)andBuffer.compare(a, b).
Instances provide write, toString, equals, numeric reads (readUInt*, readInt*, readBigInt*, readFloat*, readDouble*) and matching numeric writes. UInt/Uint aliases are available. Endian-specific methods use LE or BE.
Supported general encodings are utf8, utf-8, base64, base64url, and hex. Buffer.from() and buffer.toString() additionally accept latin1 and binary.
Base64
atob(input): string— decode base64 to Latin-1 code points;btoa(input): string— encode Latin-1; throws for characters above0xff.
URL
URL supports construction with an optional base; mutable hash, host, hostname, href, password, pathname, port, protocol, search, and username; read-only origin and searchParams; and toString()/toJSON().
URLSearchParams provides append, delete, entries, forEach, get, getAll, has, keys, set, sort, toString, values, size, and iteration.
Current declarations also mention domainToASCII and domainToUnicode, but the runtime only installs URL and URLSearchParams as globals. Do not depend on those domain helpers.
Not available
Do not assume a full browser or Node environment. In particular, use the Falz modules instead of global fetch, Node's writable fs, process, or worker APIs. An unknown runtime require() returns undefined and logs a warning; npm imports should have been bundled before runtime.