Template Runtime
The Template Runtime
Section titled “The Template Runtime”Pardon’s JSON templates are transformed and evaluated as javascript expressions. This is a synchronous evaluation to form a template object, which is then processed into a schema via merge operations.
References
Section titled “References”In pardon templates, “pure” JSON represents itself (with {{interpolations}}
). Pardon
uses any JS syntax beyond JSON for adding more structure.
For example, shorthand-property-assignement for a variable is not JSON:
{ "a": "{{a}}" }
{ a }
A value of a
is provided as a reference template object.
Reference template objects support various (chainable) operations, such as variable hinting
Hint | Description |
---|---|
ref.$hint(hint) | adds hint(s) to the reference, e.g., '?' for optional |
ref.$optional | same as `ref.$hint(’?’) — allow this value to be missing when rendering |
ref.$secret | same as `ref.$hint(’@’) — redacts this variable in non-secret contexts |
ref.$required | same as `ref.$hint(’!’) — ensures this value is present when matching |
ref.$export | same as `ref.$hint(’+’) — signals this variable for further use |
ref.$noexport | same as `ref.$hint(’-’) — does not export this variable |
ref.$distinct | same as `ref.$hint(’~’) — distinguishes a ref in keyed/multivalue contexts |
References also support typing hints
Type | Description |
---|---|
ref.$number | treat this reference as a number |
ref.$bigint | treat this reference as a bigint |
ref.$string | treat this reference as a string |
ref.$boolean | treat this reference as a boolean |
ref.$bool | same as above, but shorter |
ref.$nullable | also allow null values, renders as null when undefined |
ref.$null | same as above, but shorter |
Typing hints affect matching and rendering: when matching the value must be of the same or similar type, while when rendering a value is cast to the type when possible.
References support binding mechanisms, they can be bound to to-be-evaluated scripts.
Action | Description |
---|---|
ref.$expr(script) | declares a default value for ref as the evaluation of script (as a string) |
References support pathing, ref.x
is a reference to "ref.x"
. Since @value
and @key
are special
subpaths for scoped references, and @
is not a valid identifier, there are two path references as well:
Pathing | Description |
---|---|
ref.$value | is a reference to "ref.@value" |
ref.$key | is a reference to "ref.@key" |
For reference variable names that include hyphens, an alternate syntax is supported: $`a-b`
.
Reference Syntax Transformations
Section titled “Reference Syntax Transformations”Some of the reference API is designed to be used via syntax transformations, for instance here’s some syntax that is usually nice than using the API directly.
Syntax | Transformation |
---|---|
template1 = template2 | $merged(template2, template1) |
ref = (expr) | ref.$expr("expr") |
(expr) | $.$expr("expr") |
For references that match simple values (strings, numbers, booleans) a regex can be specified. This transforms the ref to an interpolation in the runtime, so regex can only be used in these two forms.
Syntax | Transformation |
---|---|
ref % /regex/ | "{{ ref % /regex/ }}" |
ref = (expr) % /regex/ | "{{ ref = $$expr("expr") % /regex/ }}" |
Hints and types can be applied via as type
typescript casts.
Syntax | Transformation |
---|---|
ref as optional | ref.$optional |
ref as flow | bool | ref.$optional.$boolean |
Other syntax transformations
Section titled “Other syntax transformations”Other syntax transformations are available to support representing structures and scoping with minimal syntax.
| Syntax | Transformation | notes |
| --- | --- |
| f(...)
| $f(...)
|
| a.b.f(...)
| a.b.$f(...)
|
| (expr)
| $.$expr("expr")
|
| [...template]
| $elements(template)
|
| ![...template]
| $itemOrArray(template)
|
| { key } * [...item]
| $keyed({ key }, $elements(item))
|
| { key } ** [...item]
| $keyed$mv({ key }, $elements(item))
|
| { ...template }
| $scoped(template)
|
| ref = template
| $merged(template, ref)
|
| 123
| $$number('123')
|
| ref!
| $required(ref)
|
| -ref
| $noexport(ref)
|
| +ref
| $export(ref)
|
| ~ref
| $distinct(ref)
|
In addition, /
can be used to apply template decoration functions.
| hidden / template
| $hidden(template)
|
| match / template
| $match(template)
|
match
mode mimics response processing, and this could be useful for providing literal
JSON that might contain template-like values ("{{...}}"
) that should not be treated as interpolations.
merge
is an inline merge of two templates, we’ve seen this before with reference = template
pattern but it
can be used for any binding. In most cases, merging should be distributive, e.g.,
{ a: b } = { a: 10 }
would result in the same effective schema as { a: b = 10 }
.
$$number
is a wrapper applied to numbers in JSON, it produces a new Number()
(object) with a source
field equal
to the original value. This can be a little annoying, as $$number(123) == 123
and yet $$number(123) !== 123
,
but it’s a tradeoff to allow very big numbers and arbitrary precision decimals to
not get mangled by the String(Number(original))
conversion implied by the template runtime.
Explore
Section titled “Explore”a=trueb="1024"{ a, "a-as-string": a.$string, b, "b-as-number": b.$number, c: c.$optional.$number}---{ // c: "1234" /* does not match c to number */ // c: 1234 /* matches */}