packages/@glimmer/syntax/lib/v2/README.md
AST v2 enhances the original AST with a number of clarifying features.
ASTv1 retains a node for Handlebars' "partial" syntax ({{> ...}}). ASTv2 does not include that node (just as neither version of the AST includes a node for Handlebars "decorator" syntax), as it is not supported by Glimmer.
There are a number of small naming changes that improve the clarity and precision of the AST:
hash -> namedparams -> positionalpath -> calleeSubExpression -> CallExpressionBlockStatement -> InvokeBlockMustacheStatement -> AppendContentIn ASTv1, there is a separate literal node for each kind of literal. In ASTv2, all literals are ASTv2.Literal.
In ASTv1, nodes have params and hash next to each other. In ASTv2, those nodes are grouped into an Args node that contains the positional and named arguments.
Because
ASTv2nodes are objects, this also allows these nodes to have anisEmpty()method, which makes it easy to check if a call node's arguments are totally empty.
All nodes that can have block parameters have a table: BlockSymbolTable property in ASTv2.
Elements that begin with a : are represented as ASTv2.NamedBlock.
Elements that satisfy the component heuristics are represented as ASTv2.InvokeComponent.
An element is a component if the part of its tag name before any .:
@thisElements that are not named blocks and do not satisfy the component heuristics are represented as ASTv2.SimpleElement.
The difference between strict and loose mode is entirely encapsulated in the FreeVarReference.
Consumers of ASTv2 don't need to know whether they're looking at a "strict" or "loose" template. They just need to know how to handle the different contexts in FreeVarReference.
In ASTv2, every variable name is represented as a VariableReference.
The first part of a
PathExpressionis aVariableReference.
| type | description |
| ------------------- | ------------------------------------------------------------------------------ | --- | --- |
| ThisReference | the literal this |
| ArgReference | a variable reference that begins with with @ |
| LocalVarReference | a reference to an in-scope variable binding |
| FreeVarReference | a reference to a variable binding that was not introduced by block params (as | foo | ) |
Important Note: The remainder of this README is a description of the loose mode rules for free variable resolution. Strict mode free variable references always refer to an in-scope JavaScript binding, regardless of their syntactic position.
RFC #496 (Handlebars Strict Mode) rationalized the rules for loose mode. This README describes the semantics of #496 in terms of namespaced free variable references.
There are two significant differences between strict and loose mode that affect the AST.
In loose mode, free variable references in "call" positions are resolved using a contextual namespace. For example, the free variable reference h in (h 123) is resolved as helper:h. The free variable reference h in <p {{h 123}}> is resolved as modifier:h.
In strict mode, all free variable references refer to bindings provided by a JavaScript scope that the template will be embedded within.
To represent this difference, all FreeVarReference nodes in ASTv2 are tagged with a FreeVarResolution.
The Strict resolution applies to all free variables encountered while parsing a template in strict mode.
None. Strict mode templates must be embedded in a JavaScript context where all free variable references are in scope. A compile-time error should be produced if free there are variable references that do not correspond to any in-scope variables.
| Syntax Positions | SubExpression, Block, Modifier, Component |
| Path has dots? | ❌ |
| Arguments? | Any |
| Namespace | see table below |
These resolutions occur in syntaxes that are definitely calls (e.g. subexpressions, blocks, modifiers, etc.).
| situation | variable | namespace |
|---|---|---|
(x y) | x | Helper |
{{#x y}} | x | Block |
<p {{x y}}> | x | Modifier |
X in <X /> | X | Component |
If the variable reference cannot be resolved in its namespace.
| Syntax Positions | append |
| Path has dots? | ❌ |
| Arguments? | Any |
| Namespace | helper or component |
This resolution occurs in append nodes with at least one argument, and when the path does not have dots (e.g. {{hello world}}).
| situation | variable | namespace |
|---|---|---|
{{x y}} as append | x | ComponentOrHelper |
{{x}} as append | x | ComponentOrHelper |
In this situation, the x may refer to:
xxIf the variable reference cannot be resolved in the helper or component namespaces.
This resolution context occurs in attribute nodes with zero arguments, and when the path does not have dots.
| Syntax Positions | attribute, interpolation |
| Path has dots? | ❌ |
| Arguments? | Any |
| Namespace | helper |
| situation | variable | namespace |
|---|---|---|
<p attr={{x}}> | ||
<a href="{{x}}.html"> | x | Helper |
<p attr={{x y}}> | ||
<a href="{{x y}}.html"> | x | Helper |
In this situation, the x may refer to:
xIf the variable reference cannot be resolved in the helper namespaces.
These tables apply to situations where the head of the callee's path is a free variable. When the head is a local variable, it always uses strict resolution.
Situations that meet all three of these criteria are syntax errors:
.FreeVarReference| Syntax Position | Example | Dots? | Arguments? |
|---|---|---|---|
Component | <X.y /> | ➕ | Any |
Modifier | <p {{x.y}} /> | ➕ | Any |
SubExpression | (x.y) | ➕ | Any |
Block | {{#x.y}} | ➕ | Any |
Append, Attribute | {{x.y z}} | ➕ | ➕ |
| Path has dots? | ❌ |
| Arguments? | Any |
| Syntax Position | Example | Namespace | |
|---|---|---|---|
Block | {{#x}} | block | |
Component | <X /> | component | |
Modifier | <p {{x}} /> | modifier | |
SubExpression | (x) | helper |
| Syntax Position | Example | Dots? | Args? | Namespace | |
|---|---|---|---|---|---|
Append | {{x}} | ❌ | ❌ | helper, component | |
Append | {{x.y}} | ➕ | ❌ | None | |
Append | {{x y}} | ❌ | ➕ | helper, component |
The Attribute syntax position includes:
href={{...}})@title={{...}})href="{{...}}.html")| Syntax Position | Example | Dots? | Arguments? | Namespace | |
|---|---|---|---|---|---|
Attribute | href={{x}} | ❌ | ❌ | helper | |
Attribute | href={{x.y}} | ➕ | ❌ | None | |
Attribute | href={{x y}} | ❌ | ➕ | helper |