-
Notifications
You must be signed in to change notification settings - Fork 0
Fields & Formatters
typst-mailmerge provides a set of robust, fault-tolerant field manipulation utilities designed to handle real-world CSV inconsistencies, missing fields, variations in header naming, and formatting requirements.
Retrieves a field value from a record dictionary with smart key normalization and candidate array matching.
field() automatically normalizes casing, spaces, hyphens, and underscores. For example, all of the following retrieve the same value:
field(record, "First Name")
field(record, "first_name")
field(record, "First-Name")
field(record, "firstname")If CSV datasets might vary in header naming between exports, pass an array of candidate keys. field() returns the first non-empty match:
field(record, ("First Name", "FirstName", "Given Name", "Name"))-
"upper"β Converts string to uppercase. -
"lower"β Converts string to lowercase. -
"title"β Converts string to Title Case. -
"currency"β Prepends$if not already present. - Closure
val => contentβ Custom transform function.
#field(record, "First Name", fmt: "upper") // "JANE"
#field(record, "City", fmt: "title") // "New York"
#field(record, "Balance", fmt: "currency") // "$150.00"
#field(record, "Code", fmt: v => [*#v*]) // Bold contentBinds a record dictionary to field() for ultra-concise template syntax:
#mail-merge(data, record => [
#let f = bind-field(record)
Dear #f("First Name"),
Your city is #f("City") and your balance is #f("Balance", fmt: "currency").
])Joins non-empty field values with a separator, automatically omitting missing or blank fields. Ideal for address lines, city/state pairs, or full names.
// Joins City and State cleanly: "Springfield, IL"
#join-fields(record, ("City", "State"), separator: ", ")
// Full address line joining (skips missing Address 2):
#join-fields(record, ("Address 1", "Address 2"), separator: " - ")Conditionally renders content if a field is present and non-empty:
// Render Company name only if present
#if-field(record, "Company", c => [#c \ ])
// With else block
#if-field(record, "Phone", p => [Phone: #p], [No phone provided])-
is-empty(record, key)β Returnstrueif field is empty or missing. -
is-non-empty(record, key)β Returnstrueif field is non-empty.