Handlebars - the next generation
Language specification

Literal expression

A literal expression resolves to a constant value or the following types

  • String
  • Number
  • Boolean
  • null
  • undefined

TODO: Undefined does not make sense in most non-js languages.

LiteralExpressions
Literal ::
StringLiteral
NumberLiteral
BooleanLiteral
StringLiteral ::
" AnythingExceptDoubleQuote "
' AnythingExceptSingleQuote '
AnythingExceptDoubleQuote ::
SourceCharacter but not "
AnythingExceptSingleQuote ::
SourceCharacter but not '
NumberLiteral ::
Minusopt Digits Fractionopt
Minus ::
-
Digits ::
Digit Digits
Digit :: one of
0 1 2 3 4 5 6 7 8 9
Fraction ::
. Digits
BooleanLiteral :: one of
true false

String literals

A helper parameter wrapped in double quotes is a string literal.

08-literal-expression/double-quoted-literal-string.hb-spec.json
Parameter in quotes is StringLiteral
Template:
{{id "hello"}}
Warning: The original Handlebars implementation has a deviating AST (which the author of this document considers to be wrong):
Input / Output
Input
{ "first": "hello", "second": "world" }
Helpers
id
=
Returns the first parameter
Output
hello
AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": true,
      "params": [
        {
          "type": "StringLiteral",
          "value": "hello",
          "original": "\"hello\"",
          "loc": {
            "start": { "line": 1, "column": 5 },
            "end": { "line": 1, "column": 12 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "id",
        "data": false,
        "depth": 0,
        "parts": ["id"],
        "loc": {
          "start": { "line": 1, "column": 2 },
          "end": { "line": 1, "column": 4 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 14 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 14 }
  }
}
Original AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": true,
      "params": [
        {
          "type": "StringLiteral",
          "value": "hello",
          "original": "hello",
          "loc": {
            "start": { "line": 1, "column": 5 },
            "end": { "line": 1, "column": 12 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "id",
        "data": false,
        "depth": 0,
        "parts": ["id"],
        "loc": {
          "start": { "line": 1, "column": 2 },
          "end": { "line": 1, "column": 4 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 14 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 14 }
  }
}

It can contain all characters special characters, but no double quote

08-literal-expression/double-quoted-literal-string-with-invalid-chars.hb-spec.json
Double quote string literal with special chararacters (except ").
Template:
{{{id "! #%&'()*+,;<=>@[\]^`{|}~"}}}
Warning: The original Handlebars implementation has a deviating AST (which the author of this document considers to be wrong):
Input / Output
Input
{}
Helpers
id
=
Returns the first parameter
Output
! #%&'()*+,;<=>@[\]^`{|}~
AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": false,
      "params": [
        {
          "type": "StringLiteral",
          "value": "! #%&'()*+,;<=>@[\\]^`{|}~",
          "original": "\"! #%&'()*+,;<=>@[\\]^`{|}~\"",
          "loc": {
            "start": { "line": 1, "column": 6 },
            "end": { "line": 1, "column": 33 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "id",
        "data": false,
        "depth": 0,
        "parts": ["id"],
        "loc": {
          "start": { "line": 1, "column": 3 },
          "end": { "line": 1, "column": 5 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 36 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 36 }
  }
}
Original AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": false,
      "params": [
        {
          "type": "StringLiteral",
          "value": "! #%&'()*+,;<=>@[\\]^`{|}~",
          "original": "! #%&'()*+,;<=>@[\\]^`{|}~",
          "loc": {
            "start": { "line": 1, "column": 6 },
            "end": { "line": 1, "column": 33 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "id",
        "data": false,
        "depth": 0,
        "parts": ["id"],
        "loc": {
          "start": { "line": 1, "column": 3 },
          "end": { "line": 1, "column": 5 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 36 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 36 }
  }
}

A helper parameter wrapper in single quotes can contain all characters except a single quote.

08-literal-expression/single-quoted-literal-string-with-invalid-chars.hb-spec.json
Single quote string literal with special chararacters (except ').
Template:
{{{id '! #%&"()*+,;<=>@[\]^`{|}~'}}}
Warning: The original Handlebars implementation has a deviating AST (which the author of this document considers to be wrong):
Input / Output
Input
{}
Helpers
id
=
Returns the first parameter
Output
! #%&"()*+,;<=>@[\]^`{|}~
AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": false,
      "params": [
        {
          "type": "StringLiteral",
          "value": "! #%&\"()*+,;<=>@[\\]^`{|}~",
          "original": "'! #%&\"()*+,;<=>@[\\]^`{|}~'",
          "loc": {
            "start": { "line": 1, "column": 6 },
            "end": { "line": 1, "column": 33 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "id",
        "data": false,
        "depth": 0,
        "parts": ["id"],
        "loc": {
          "start": { "line": 1, "column": 3 },
          "end": { "line": 1, "column": 5 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 36 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 36 }
  }
}
Original AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": false,
      "params": [
        {
          "type": "StringLiteral",
          "value": "! #%&\"()*+,;<=>@[\\]^`{|}~",
          "original": "! #%&\"()*+,;<=>@[\\]^`{|}~",
          "loc": {
            "start": { "line": 1, "column": 6 },
            "end": { "line": 1, "column": 33 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "id",
        "data": false,
        "depth": 0,
        "parts": ["id"],
        "loc": {
          "start": { "line": 1, "column": 3 },
          "end": { "line": 1, "column": 5 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 36 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 36 }
  }
}

Number literals

08-literal-expression/number-literal.hb-spec.json
A parameter without quotes, consisting of digits and a dot, is a NumberLiteral
Template:
{{add 64 -00064.5}}
Warning: The original Handlebars implementation has a deviating AST (which the author of this document considers to be wrong):
Input / Output
Input
{}
Helpers
add
=
Adds two numbers
Output
-0.5
AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": true,
      "params": [
        {
          "type": "NumberLiteral",
          "value": 64,
          "original": "64",
          "loc": {
            "start": { "line": 1, "column": 6 },
            "end": { "line": 1, "column": 8 }
          }
        },
        {
          "type": "NumberLiteral",
          "value": -64.5,
          "original": "-00064.5",
          "loc": {
            "start": { "line": 1, "column": 9 },
            "end": { "line": 1, "column": 17 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "add",
        "data": false,
        "depth": 0,
        "parts": ["add"],
        "loc": {
          "start": { "line": 1, "column": 2 },
          "end": { "line": 1, "column": 5 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 19 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 19 }
  }
}
Original AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": true,
      "params": [
        {
          "type": "NumberLiteral",
          "value": 64,
          "original": 64,
          "loc": {
            "start": { "line": 1, "column": 6 },
            "end": { "line": 1, "column": 8 }
          }
        },
        {
          "type": "NumberLiteral",
          "value": -64.5,
          "original": -64.5,
          "loc": {
            "start": { "line": 1, "column": 9 },
            "end": { "line": 1, "column": 17 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "add",
        "data": false,
        "depth": 0,
        "parts": ["add"],
        "loc": {
          "start": { "line": 1, "column": 2 },
          "end": { "line": 1, "column": 5 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 19 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 19 }
  }
}

Boolean literals

08-literal-expression/true-literal.hb-spec.json
The literal 'true' is passed as boolean to helpers
Template:
{{if_then_else true 'yes' 'no'}}
Warning: The original Handlebars implementation has a deviating AST (which the author of this document considers to be wrong):
Input / Output
Input
{}
Helpers
if_then_else
=
returns seconds param if first is true, otherwise the third
Output
yes
AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": true,
      "params": [
        {
          "type": "BooleanLiteral",
          "value": true,
          "original": "true",
          "loc": {
            "start": { "line": 1, "column": 15 },
            "end": { "line": 1, "column": 19 }
          }
        },
        {
          "type": "StringLiteral",
          "value": "yes",
          "original": "'yes'",
          "loc": {
            "start": { "line": 1, "column": 20 },
            "end": { "line": 1, "column": 25 }
          }
        },
        {
          "type": "StringLiteral",
          "value": "no",
          "original": "'no'",
          "loc": {
            "start": { "line": 1, "column": 26 },
            "end": { "line": 1, "column": 30 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "if_then_else",
        "data": false,
        "depth": 0,
        "parts": ["if_then_else"],
        "loc": {
          "start": { "line": 1, "column": 2 },
          "end": { "line": 1, "column": 14 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 32 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 32 }
  }
}
Original AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": true,
      "params": [
        {
          "type": "BooleanLiteral",
          "value": true,
          "original": true,
          "loc": {
            "start": { "line": 1, "column": 15 },
            "end": { "line": 1, "column": 19 }
          }
        },
        {
          "type": "StringLiteral",
          "value": "yes",
          "original": "yes",
          "loc": {
            "start": { "line": 1, "column": 20 },
            "end": { "line": 1, "column": 25 }
          }
        },
        {
          "type": "StringLiteral",
          "value": "no",
          "original": "no",
          "loc": {
            "start": { "line": 1, "column": 26 },
            "end": { "line": 1, "column": 30 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "if_then_else",
        "data": false,
        "depth": 0,
        "parts": ["if_then_else"],
        "loc": {
          "start": { "line": 1, "column": 2 },
          "end": { "line": 1, "column": 14 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 32 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 32 }
  }
}

08-literal-expression/false-literal.hb-spec.json
The literal 'false' is passed as boolean to helpers
Template:
{{if_then_else false 'yes' 'no'}}
Warning: The original Handlebars implementation has a deviating AST (which the author of this document considers to be wrong):
Input / Output
Input
{}
Helpers
if_then_else
=
returns seconds param if first is true, otherwise the third
Output
no
AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": true,
      "params": [
        {
          "type": "BooleanLiteral",
          "value": false,
          "original": "false",
          "loc": {
            "start": { "line": 1, "column": 15 },
            "end": { "line": 1, "column": 20 }
          }
        },
        {
          "type": "StringLiteral",
          "value": "yes",
          "original": "'yes'",
          "loc": {
            "start": { "line": 1, "column": 21 },
            "end": { "line": 1, "column": 26 }
          }
        },
        {
          "type": "StringLiteral",
          "value": "no",
          "original": "'no'",
          "loc": {
            "start": { "line": 1, "column": 27 },
            "end": { "line": 1, "column": 31 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "if_then_else",
        "data": false,
        "depth": 0,
        "parts": ["if_then_else"],
        "loc": {
          "start": { "line": 1, "column": 2 },
          "end": { "line": 1, "column": 14 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 33 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 33 }
  }
}
Original AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": true,
      "params": [
        {
          "type": "BooleanLiteral",
          "value": false,
          "original": false,
          "loc": {
            "start": { "line": 1, "column": 15 },
            "end": { "line": 1, "column": 20 }
          }
        },
        {
          "type": "StringLiteral",
          "value": "yes",
          "original": "yes",
          "loc": {
            "start": { "line": 1, "column": 21 },
            "end": { "line": 1, "column": 26 }
          }
        },
        {
          "type": "StringLiteral",
          "value": "no",
          "original": "no",
          "loc": {
            "start": { "line": 1, "column": 27 },
            "end": { "line": 1, "column": 31 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "if_then_else",
        "data": false,
        "depth": 0,
        "parts": ["if_then_else"],
        "loc": {
          "start": { "line": 1, "column": 2 },
          "end": { "line": 1, "column": 14 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 33 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 33 }
  }
}

08-literal-expression/path-starting-with-boolean.hb-spec.json
A path starting with false or true is still a path
Template:
{{add false_ true_}}
Input / Output
Input
{ "false_": 1, "true_": 2 }
Helpers
add
=
Adds two numbers
Output
3
AST
{
  "type": "Program",
  "body": [
    {
      "type": "MustacheStatement",
      "escaped": true,
      "params": [
        {
          "type": "PathExpression",
          "original": "false_",
          "data": false,
          "depth": 0,
          "parts": ["false_"],
          "loc": {
            "start": { "line": 1, "column": 6 },
            "end": { "line": 1, "column": 12 }
          }
        },
        {
          "type": "PathExpression",
          "original": "true_",
          "data": false,
          "depth": 0,
          "parts": ["true_"],
          "loc": {
            "start": { "line": 1, "column": 13 },
            "end": { "line": 1, "column": 18 }
          }
        }
      ],
      "path": {
        "type": "PathExpression",
        "original": "add",
        "data": false,
        "depth": 0,
        "parts": ["add"],
        "loc": {
          "start": { "line": 1, "column": 2 },
          "end": { "line": 1, "column": 5 }
        }
      },
      "strip": { "open": false, "close": false },
      "loc": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 20 }
      }
    }
  ],
  "strip": {},
  "loc": {
    "start": { "line": 1, "column": 0 },
    "end": { "line": 1, "column": 20 }
  }
}