Syntax
This page describes the concrete syntax you type when writing a FLASH block.
FLASH has two “contexts” that matter when you read the syntax:
- FHIR target context: where a rule writes in the output resource.
- Input context: what expressions (on the right-hand side) evaluate against.
If you’re looking for how those contexts behave at runtime (fan-out, append vs override, type shaping), see Evaluation model.
Declarations
A FLASH block starts with declarations that establish the output resource type (and optionally its id).
InstanceOf: (required)
InstanceOf: declares the FHIR type or profile identifier for the block.
InstanceOf: Patient
InstanceOf: accepts a single identifier token, such as:
- a base type name (for example:
Patient,Encounter,Observation) - a profile identifier from your definition set (for example:
observation-bp) - a canonical URL (for example:
http://hl7.org/fhir/StructureDefinition/Patient)
If the identifier can’t be parsed as a single token, the block fails at parse-time. If it parses but can’t be resolved in the active definition set, evaluation fails at definition-resolution time (covered in Diagnostics).
Instance: (optional)
Instance: computes an instance id for the resource. When present, it behaves like writing an id rule before the rest of the rule list.
Instance: $uuid('ExampleCare-Patient-001')
InstanceOf: Patient
* active = true
Placement and ordering:
Instance:appears at most once.- When present,
Instance:is the first line of the block and is immediately followed byInstanceOf:on the next line. InstanceOf:appears exactly once.
Instance: is an expression. It can be a literal string, a function call, or a complete parenthesis block. The expression must evaluate to a string or a primitive value that can safely be converted to a string.
Rule forms
After declarations, the block contains a list of rule lines and (optionally) variable bindings.
Rule lines start with * (after any indentation).
Assignment rule
An assignment rule writes the result of an expression (right-hand side of the =) into a FHIR target path.
InstanceOf: Patient
* active = true
* birthDate = "1985-01-23"
Form:
* <path> = <expr>
Context rule (target nesting)
A context rule sets the FHIR target context for nested rules. Nested rules are indented beneath the parent.
InstanceOf: Patient
* name
* family = "ExampleCare"
* given = "Avery"
Form:
* <path>
* <child-path> = <expr>
* <child-path>
...
Empty rule
It’s also valid to write a context rule with no right-hand side and no nested rules:
InstanceOf: Observation
* code.coding[ExampleCarePanel]
This “empty rule” form is used to materialize/validate the target element (for example, to force creation/selection of a sliced entry) without directly assigning a value on that line.
Input-context rule (input focus for nested evaluation)
An input-context rule changes the input context used by nested expressions, while the FHIR target context is still defined by the rule’s path.
InstanceOf: Patient
* (phones).telecom
* system = "phone"
* value = $
Form:
* (<expr>).<path>
...nested rules...
The same shape can also be used as a single-line assignment:
InstanceOf: Patient
* (patientId).id = $
If the input-context expression evaluates to an array, the nested rule set is evaluated once per item. JSONata focus/index binding syntax (like @$value and #$index) can be used inside the parentheses to control what $ and bound variables refer to.
Variable bindings inside a block
Variable bindings use JSONata’s assignment operator and are allowed inside a FLASH block.
InstanceOf: Patient
$fullName := firstName & " " & lastName
* name.text = $fullName
Form:
$name := <expr>
Within a FLASH block, lines that are neither rules (* ...) nor variable bindings ($name := ...) are rejected.
Indentation and blocks
FLASH uses indentation to express nesting.
- Nesting depth advances in 2-space increments.
- A nested line has greater indentation than its parent line.
- Decreasing indentation closes blocks.
- Mixing indentation widths (for example, 1 space) produces parse-time indentation errors.
The stable convention is 2 spaces per level. Tabs are accepted as indentation, but they’re easy to misalign visually; 2 spaces avoids “looks aligned, parses misaligned” failures.
Example with two nesting levels:
InstanceOf: Patient
* name
* period
* start = "2020-01-01"
Example of “continue a long path” using blocks (instead of trying to split a path across lines):
InstanceOf: Patient
* identifier
* assigner
* reference = "Organization/examplecare"
Paths and slices
Rule paths target FHIR JSON element names.
Path segments
- Paths are dot-separated segments:
a.b.c. - Segments are simple name tokens (they are not expressions).
- Paths cannot be split across lines.
Multi-step paths are allowed on one line:
InstanceOf: Patient
* name.family = "ExampleCare"
If you prefer, the same write can be expressed using a context rule:
InstanceOf: Patient
* name
* family = "ExampleCare"
Choice types
When a FHIR element is a choice type (like value[x]), rule paths use the concrete JSON name (for example: valueQuantity, valueString, valueCodeableConcept).
InstanceOf: Observation
* valueQuantity = 180
Slice selectors with brackets
Brackets in FLASH paths are used for slice/profile selection, not array indexing.
InstanceOf: Patient
* identifier[ExampleCareMrn]
* system = "urn:examplecare:mrn"
* value = mrn
Slice selectors behave like element[sliceId], where sliceId is a legal slice identifier (often a simple name; some slices can be targeted via canonical identifiers/URLs, depending on how your definitions are authored).
Invalid patterns for brackets include:
name[0](indexing)identifier[1+2](expressions)coding[slice with spaces](non-token selectors)
Comments and whitespace
For the canonical comment rules, see Comments.
Inside FLASH blocks, comments can appear on their own line or after a rule.
InstanceOf: Patient
// ExampleCare demo mapping
* active = true /* inline note */
Blank lines are allowed.
FLASH-specific gotcha: when Instance: is present, InstanceOf: immediately follows it as the next non-comment line. Putting other content between them is treated as a parse error.
Common syntax errors
- Missing
InstanceOf:: a block with rules but noInstanceOf:does not parse. - Separated headers: when using
Instance:, placing anything betweenInstance:andInstanceOf:causes a parse-time error. - Wrong assignment operator:
:=is for$variables; rule assignments use=. - Invalid indentation: indentation that isn’t a 2-space multiple (or that doesn’t line up with an open block) fails at parse-time.
- Using
$in a FLASH rule target path:$variables belong in expressions (right-hand side of the=), not in rule paths. - Trying to index with brackets:
name[0]is not valid FLASH; brackets denote slice/profile selection by name, never by numeric indices. - Splitting a path across lines: use a context rule to continue on the next line.
- Semicolons inside object literals:
{ "a": 1; "b": 2 }is not valid.