Skip to main content
penscript provides a full set of operators for working with collections — iterating, transforming, filtering, querying, and building arrays. These are used to generate dynamic form fields, validate uploaded documents, compute aggregates, and build conditional structures based on variable-length data.

Context Variables

When iterating over an array (with :map, :every, :some, :find, or :filter), penscript makes the following context variables available inside the loop body: Access nested properties of the current item with dot notation: {@item.name}, {@item.role}, {@item.amount}.

Normalizing to Arrays: :array

Wraps a value in an array if it isn’t one already. Useful for ensuring consistent array input when a value might be a single item or an array.

Generating Arrays with :fill

Combine :array with :fill to generate arrays of a specific length. Each element is created from the :fill template, with context variables available.

Mapping: :map

Transforms every item in an array. The transformation expression has access to {@item}, {@index}, {@position}, {@first}, and {@last}. Using :to syntax:
Using array syntax — the second element is the transformation expression:
Complex mapping with local variables using :with: This is the most powerful pattern — generating dynamic structures from data. The :with operator creates local variables for each iteration, keeping the template readable.

Filtering: :filter

Removes items from an array based on a condition. Works by mapping items to themselves (kept) or false (removed), then stripping the falsy values.
Filtering with inline expressions:

Finding Items: :find

Returns the first item in an array that matches a condition. If no match is found, returns undefined.

Membership & Intersections

:includes

Tests if an array contains a specific value.
Works with :if for access control patterns:

:intersects

Tests if two arrays share any common elements.

Counting: :count

Returns the number of items in an array.

Conditional Counting with :where

Count only items that satisfy a condition:

Excluding Items with :unless

Combine :where and :unless for fine-grained filtering:

Range Arrays: :range-array

Generates an array of sequential integers. The start is inclusive, the end is exclusive.
Commonly used with :map to generate a dynamic number of form fields or UI elements based on a user-provided count.

Flattening: :flatten

Deeply flattens nested arrays into a single flat array.
Useful after a :map that produces arrays of arrays — for example, when each mapped item generates multiple form fields and you need them in a single flat list.

Sequence Check: :increasing

Returns true if all values in the array are in strictly increasing order.
Useful for validating that sequential inputs are in the expected order (e.g., dates, amounts, installment schedules).

Next Steps

Logic & comparisons

:every and :some for array conditions

Numbers & calculations

Aggregate calculations on arrays

Variables & scope

Context variables in loops

How penscript works

Dynamic form generation with :map