Skip to main content

Authoring Templates

Template authoring follows a similar process to Typescript expansion rule authoring.

To create a new sequence template for an activity type (or to edit existing ones) navigate to the Sequence Templates page of Aerie.

Aerie UI - Templates Page
Figure 1: Navigating to the sequence templates page

To create a new template, select New Template, and provide your template with:

  • a name
  • a sequencing language, currently restricted to: STOL, SeqN, or Text
    • (this setting enables editor syntax highlighting for supported languages, but arbitrary languages may be used with the "Text" setting)
  • a parcel ID (to get the set of allowed commands from the dictionary)
  • a model ID (to enable access to the activity types)
  • and the activity type that this template is for

To edit an existing template, mouse over it in the table and select the edit button.

Aerie UI - Create New Template
Figure 2: Creating a new sequence template

This editor has autocomplete functionality, whitespace formatting, and error visibility for supported languages. There is also a panel that describes the available commands, one describing the template, and the ability to switch to editing a different sequence template.

Aerie UI - Template Editor
Figure 3: Template Editor

Finally, you can save your result, and you are now ready to expand using this template.

Using the Handlebars template language

Sequence templates are written in the Handlebars template language. This language allows users to embed variables from some input (more on the input shortly) into a body of text. For example, if I had the following:

Input

{ input: "bananas" }

Template

I like to eat {{ input }}.

and compiled these together using Handlebars, I would get as a result:

Result

I like to eat bananas.

This is useful for expanding activities because, as discussed in the Introduction, it allows us directly write sequence templates with expressions, which more closely resemble the final expanded sequences than rules did. To reuse our earlier example, the template:

C BOOT_COPY_NOR_IMAGE "ZONE_0" "ZONE_1"
A2024-123T00:00:00 AVS_PCE_MEMORY_POKE {{ attributes.arguments.quantity }} "string"
C EP_XFC_LV_CLOSE "XFC_A"
C DP_PRIORITIZE "STRING" {{ attributes.arguments.quantity }}

compiles to this very similar looking result:

Result

C BOOT_COPY_NOR_IMAGE "ZONE_0" "ZONE_1"
A2024-123T00:00:00 AVS_PCE_MEMORY_POKE 5 "string"
C EP_XFC_LV_CLOSE "XFC_A"
C DP_PRIORITIZE "STRING" 5

Template input data

During expansion, Aerie goes through your plan looking for activities which have a template associated with them, and compiles the template with the following input data structure from the activity, which may be used in the template:

{
id: number; // ID of the activity instance
simulationDatasetId: number; // ID of the associated simulation dataset
simulationDataset: {
simulation: {
planId: number // ID of the associated plan
}
};
attributes: {
arguments: { ... }; // arguments provided to the activity
directiveId: number; // ID of the associated activity directive
computed: { ... }; // activity's computed attributes
};
duration: Temporal.Duration; // duration of the activity
startOffset: Temporal.Duration; // start offset of the activity from its parent, or the beginning of the plan
startTime: Temporal.Instant; // start time of the activity
endTime: Temporal.Instant; // end time of the activity
activityTypeName: string; // name of the associated activity type
}

So, to access the activity type name, followed by the end time, and then a computed argument by the name of quantity, one could write:

CMD {{ activityTypeName }} endsAt={{ endTime }} quantity={{ attributes.arguments.quantity }}

The actual compilation of templates is discussed in Expanding Templates.

Template Helpers

We also introduce with Handlebars formatting the notion of helpers. Helper functions (discussed in the Handlebars documentation here), allow a user to invoke a function with arguments and produce a result in the template. Aerie defines 4 helpers for use in templates. User-defined helpers are not yet supported, so only these 4 are available at the moment.

add-time

This helper allows a user to compute a new time string (that is either STOL or SeqN compatible) from an existing one, and a duration to be added to that time. For example:

Input

{
...,
startTime: "2024-001T00:00:00",
attributes: {
...,
arguments: {
...,
growingDuration: "01:00:00"
}
}
}

Template

A{{ add-time startTime attributes.arguments.growingDuration }}

compiles to:

Result

A2024-001T01:00:00

subtract-time

This helper allows a user to compute a new time string (that is either STOL or SeqN compatible) from an existing one, and a duration to be subtracted from that time. For example:

Input

{
...,
startTime: "2024-001T00:00:00",
attributes: {
...,
arguments: {
...,
growingDuration: "01:00:00"
}
}
}

Template

A{{ subtract-time startTime attributes.arguments.growingDuration }}

which compiles to:

Result

A2023-365T23:00:00

format-as-date

This helper allows a user to format a date-like string input in the date format defined in the target sequencing language. For example, if I want STOL-like dates (which use / instead of a T, and include the time zone abbreviation) but my input is:

Input

{
...,
startTime: "2025-001T00:00:00.00
}

then I can write my template as:

Template

CMD AT={{ format-as-date startTime }}

which provides me with:

Result

CMD AT=2025-001/00:00:00Z
Note

If the sequencing language is Text, it is preferred that users include the Zulu time abbreviation in their input data. Currently, if it is left out, and the date is formatted as a YYYY-MM-DD string, the date is automatically converted to the current time zone, which produces some inconsistency in output.

flatten

This helper allows a user to format arrays correctly according to the target sequencing language. SeqN array formatting looks a little different than conventional array formatting in Handlebars, which we illustrate below:

Input

{
...,
attributes: {
...,
arguments: {
...,
array: [1, 2, 3, 3.5, "string"]
}
}
}

Template

Unflattened: {{ firstArraySet }}; Flattened: {{ flatten firstArraySet }}

compiles to:

Result

Unflattened: 1,2,3.5,string; Flattened: [1 2 3.5 string]

Putting this all together in AERIE, we might have the following:

Aerie UI - Template With Helpers
Figure 4: A sequence template using helpers

Other Notes

There are some quirks to our application of the Handlebars language to sequence templates. Some of the least intuitive parts are listed below, please refer to the official Handlebars documentation for language details before filing an issue for any quirks you may notice.

Missing inputs/helpers

If you refer to an input variable or helper that is not present in the input object or the helpers library, it is considered invalid and will produce an empty string in the compiled output, for example:

Template

ECHO "{{ badInputVariable }}"

compiles to

Result

ECHO ""

HTML/XML-like String Escaping

HTML string escaping (should any inputs coming from a simulated activity have XML-like strings) is automatic in Handlebars. That is, if we have:

Input

{
name: "<name>"
}

Template

I am {{ name }}.

it will compile to:

Result

I am &lt;name&gt;.

This can be avoided by using triple brackets:

Input

{
name: "<name>"
}

Template

I am {{{ name }}}.

will compile to:

Result

I am <name>.

Helper functions will still be correctly applied to expressions in triple brackets.

Arrays and Objects

Arrays and objects also have particular behavior. There currently exists no well-defined behavior for objects, so the default behavior of resolving to the string [Object object] for any given object is used. For arrays, if the flatten helper isn't used, the array is serialized as a list of comma-separated elements WITHOUT brackets. That is:

Input

{
array: [1, 2, 3],
object: {
arbitrary: {
property1: "a",
property2: "b",
},
important: "item"
}
}

Template

Array: {{ array }}
Object: {{ object }}

will compile to:

Result

Array: 1,2,3
Object: [Object object]