The complete set of functions available inside process.js - plain
JavaScript, running once per submission after validate.js passes. See
process.js for the bigger picture (inputs,
when it runs, handing computed data to blocks); this page is the exhaustive
function-by-function reference.
Console
console.log(), console.warn(), and console.error() all work inside
process.js (and validate.js) - but there's
no browser or terminal for their output to appear in. Instead, every call
is redirected into that submission's processing trace - the same
in-app Processing Log / debug.log file covered on the
Debugging page. console.warn()/
console.error() calls specifically are what turn the Processing Log
button amber/red.
console.log("line items:", inputs.line_items.length);
if (inputs.line_items.length > 50) {
console.warn("more than 50 line items - page may run long");
}
console.error(msg) is also a clean way to bail out of your own script with
an explanation: it records the ERROR: line same as console.warn/
console.log do, then halts the rest of the script - same as any other
uncaught error already does. There's no exception for "an error a script
raises on purpose" - any error halts processing.
Multiple arguments are joined with a space; a plain string passes through
as-is, anything else (a number, object, array) is JSON.stringify()'d
first - so console.log("bounds:", getBlockBounds(1)) prints something
like bounds: {"x":10,"y":20,"width":30,"height":40}.
Pages
addPage(properties)
Declares one output page. Page number = position in the call sequence - the
first call produces page 1, the second page 2, and so on. Two shapes,
discriminated by whether pdf is present:
addPage({ width: 80, height: 200, backgroundColor: "#FFFFFF" });
// blank, synthesized page - width/height required (mm), backgroundColor
// optional hex, default "#FFFFFF"
addPage({ pdf: "base.pdf", pdfPage: 1 });
// backed by page 1 (default) of a project-relative PDF resource file - an
// ordinary named asset, not one blessed "base.pdf" filename. width/height
// are optional overrides that stretch-fit the rasterized page; omitted,
// the page's own natural size is used.
A document with no addPage() calls at all fails to generate -
required, no fallback. A malformed call (no usable width/height or
pdf resource, an unreadable pdf resource, an out-of-range pdfPage)
halts processing immediately, the same as any other host function error
below.
overlay(filename[, page[, transform]])
Loads a layout partial and merges its blocks
into the page named by page (default 1, an addPage()-declared page
number - must already exist, or this halts processing). Callable more than
once, targeting different pages or reusing the same partial with a
different transform each time. Later calls paint in front of earlier
ones whenever z_index ties.
Halts processing if filename doesn't exist or isn't valid JSON. A single
malformed block within an otherwise-valid partial (missing a required
key, wrong type) is skipped instead - a warning in the Processing Log, not
a halt.
transform (all fields optional):
| Field | Effect |
|---|---|
dx_mm, dy_mm |
Shift every merged block's x_mm/y_mm (default 0) |
rotate_deg |
Adds to each block's own rotation_deg (default 0) - a value of exactly 180 (or an equivalent like -180/540) also repositions every block via a point-reflection through the group's own bounding-box center; any other angle only spins content in place |
scale_x, scale_y |
Multiply each block's own scale_x/scale_y (default 1) - content-only, never touches x_mm/y_mm/width_mm/height_mm |
align_top_mm, align_bottom_mm |
Replaces dy_mm - shifts the group so its own top/bottom edge lands at this absolute y_mm, recomputed from current geometry every call |
addPage({ width: 210, height: 297, backgroundColor: "#FFFFFF" });
overlay("overlay.json");
overlay("mask.json", 1, { dx_mm: 40, rotate_deg: 180, scale_x: -1 });
Repeating the same partial at several hand-computed positions (a card design placed six times on a sheet, say) can also be done visually, with an Overlay block placed directly in the Overlay Editor instead of a script loop - see the
overlayblock type on {overlay}.json.
Page refinement
Four functions that adjust an already-addPage()'d page. All four act
immediately, ordinary and order-sensitive like everything else in
process.js - a call reflects (or changes) whatever's true in the model
at that exact point in the script, not some later, fully-resolved state.
There's no re-run of any kind: process.js always runs exactly once, top
to bottom.
setPageHeight(page, height) / setPageWidth(page, width)
Set that page's height/width directly and literally, replacing
whatever it was - no implicit "trim to content" computation. The primary
tool for variable-length pages - receipts, or any layout whose content
extent isn't known until the script finishes (a repeating line-items
loop, for example) - is composing this from getBlockBounds() yourself:
addPage({ width: 80, height: 500, backgroundColor: "#FFFFFF" }); // generous ceiling
overlay("header.json");
var y = 35;
for (var i = 0; i < inputs.line_items.length; i++) {
overlay("line_item.json", 1, { dy_mm: y });
y += 6;
}
overlay("totals.json", 1, { dy_mm: y });
var b = getBlockBounds(1);
setPageHeight(1, b.y + b.height + 5); // trim to (max block bottom) + 5mm
Calling this more than once for the same page: the last call wins, plainly - each call just overwrites the page's height/width, nothing more. A PDF-resource-backed page can only ever shrink, never grow past its current size (a call that would grow it is silently clamped, with a warning in the Processing Log - background rasters can be cropped smaller but not stretched larger without visibly degrading).
setPageTransform(page, transform) / setTransform(transform)
Same transform shape overlay() takes. setPageTransform sets it as a
property of that page; setTransform (no page argument) sets it for the
whole document. Either way, it's resolved once, at generation time, over
every block on the page (or every page, for setTransform) - including
ones added by an overlay() call that comes after this one in the
script - never a retroactive rewrite of a block's own stored x_mm/y_mm/
etc. setTransform composes over every page's own setPageTransform, as
the outermost layer.
One important difference from overlay()'s own scale_x/scale_y:
here they're geometric, not content-only - they multiply x_mm and
width_mm together (resp. y_mm/height_mm), anchored at the page's own
origin. That's what makes this actually useful for its main purpose:
// The physical printer is 77mm wide, but this content was designed for 80mm.
addPage({ width: 77, height: 200, backgroundColor: "#FFFFFF" }); // real physical width
overlay("receipt_content.json"); // authored assuming 80mm
setPageTransform(1, { scale_x: 77 / 80 }); // remaps content to fit; addPage()'s width/height stays untouched
Queries
Three functions that read geometry the script can't compute itself.
Each is a plain, synchronous read of whatever's true in the model at the
moment it's called - the same as reading a property off any ordinary
object mid-construction. Calling one for a page that hasn't been
addPage()'d yet halts processing, same as overlay()/setPageHeight()
would for the same mistake.
getBlockBounds(page)
Returns {x, y, width, height} in mm - the union rectangle of everything
placed on that page so far - or null if the page has no blocks yet.
getPageSize(page)
Returns {width, height} in mm - that page's own current size, reflecting
a setPageHeight()/setPageWidth() call already made. Mostly useful for
a PDF-resource-backed page with no explicit override, where the real
rasterized size otherwise isn't knowable from the script.
getPdfPageSize(file, pdfPage)
Returns {width, height} in mm - the natural size of a page of a PDF
resource file, independent of any addPage() call (no page needs to
reference it first). Halts processing for a missing file or out-of-range
page, same as any other host function error.
Project introspection
Four read-only lookups - every value here is knowable before process.js
even starts running, so unlike the queries above, none of these depend on
where in the script you call them.
| Function | Returns |
|---|---|
getProject() |
{name, description, notes, categories, defaultWidthMm, defaultHeightMm, defaultBackgroundColor} - project.ypf's own metadata |
listAssets() |
{images, fonts, pdfs} - the project folder's own files, each a sorted array of filenames |
getFormFields() |
[{id, type, label, fields}] - form.json's field tree; fields is non-empty only for a repeating group, recursing into its own child fields |
getImageDimensions(file) |
{width, height} in pixels (not mm), or null for a missing/undecodable/SVG file |
var project = getProject();
if (project.categories.indexOf("automotive") != -1) {
overlay("dealer_disclaimer.json");
}
if (listAssets().images.indexOf("dealer_logo.png") != -1) {
overlay("logo.json");
}
Formatting
Plain JavaScript, not locale-aware - useful shorthand, not a substitute for real internationalization.
| Function | Example |
|---|---|
formatNumber(value, decimals) |
formatNumber(1234.5) → "1,234.50" (decimals default 2) |
formatCurrency(value, currencyCode) |
formatCurrency(1234.5) → "$1,234.50"; formatCurrency(-5, "EUR") → "-€5.00" (default "USD"; USD/EUR/GBP/JPY get a real symbol, any other code prints as "CODE "; JPY defaults to 0 decimals) |
formatDate(value, pattern) |
formatDate(new Date(2024, 0, 5)) → "2024-01-05" (default pattern "YYYY-MM-DD"); pattern tokens: YYYY, MM, DD, HH, mm, ss |