225 lines
4.9 KiB
Markdown
225 lines
4.9 KiB
Markdown
# Handlebars Compiler APIs
|
|
|
|
There are a number of formal APIs that tool implementors may interact with.
|
|
|
|
## AST
|
|
|
|
Other tools may interact with the formal AST as defined below. Any JSON structure matching this pattern may be used and passed into the `compile` and `precompile` methods in the same way as the text for a template.
|
|
|
|
AST structures may be generated either with the `Handlebars.parse` method and then manipulated, via the `Handlebars.AST` objects of the same name, or constructed manually as a generic JavaScript object matching the structure defined below.
|
|
|
|
```javascript
|
|
var ast = Handlebars.parse(myTemplate);
|
|
|
|
// Modify ast
|
|
|
|
Handlebars.precompile(ast);
|
|
```
|
|
|
|
|
|
### Basic
|
|
|
|
```java
|
|
interface Node {
|
|
type: string;
|
|
loc: SourceLocation | null;
|
|
}
|
|
|
|
interface SourceLocation {
|
|
source: string | null;
|
|
start: Position;
|
|
end: Position;
|
|
}
|
|
|
|
interface Position {
|
|
line: uint >= 1;
|
|
column: uint >= 0;
|
|
}
|
|
```
|
|
|
|
### Programs
|
|
|
|
```java
|
|
interface Program <: Node {
|
|
type: "Program";
|
|
body: [ Statement ];
|
|
|
|
blockParams: [ string ];
|
|
strip: StripFlags | null;
|
|
}
|
|
```
|
|
|
|
### Statements
|
|
|
|
```java
|
|
interface Statement <: Node {
|
|
strip: StripFlags | null;
|
|
}
|
|
|
|
interface MustacheStatement <: Statement {
|
|
type: "MustacheStatement";
|
|
sexpr: Subexpression;
|
|
escaped: boolean;
|
|
}
|
|
|
|
interface BlockStatement <: Statement {
|
|
type: "BlockStatement";
|
|
sexpr: Subexpression;
|
|
program: Program;
|
|
inverse: Program | null;
|
|
}
|
|
|
|
interface PartialStatement <: Statement {
|
|
type: "PartialStatement";
|
|
sexpr: Subexpression;
|
|
|
|
indent: string;
|
|
}
|
|
|
|
interface ContentStatement <: Statement {
|
|
type: "ContentStatement";
|
|
value: string;
|
|
original: string;
|
|
}
|
|
|
|
interface CommentStatement <: Statement {
|
|
type: "CommentStatement";
|
|
value: string;
|
|
}
|
|
```
|
|
|
|
### Expressions
|
|
|
|
```java
|
|
interface Expression <: Node { }
|
|
```
|
|
|
|
##### Subexpressions
|
|
|
|
```java
|
|
interface SubExpression <: Expression {
|
|
type: "SubExpression";
|
|
path: PathExpression;
|
|
params: [ Expression ];
|
|
hash: Hash;
|
|
|
|
isHelper: true | null;
|
|
}
|
|
```
|
|
|
|
`isHelper` is not required and is used to disambiguate between cases such as `{{foo}}` and `(foo)`, which have slightly different call behaviors.
|
|
|
|
##### Paths
|
|
|
|
```java
|
|
interface PathExpression <: Expression {
|
|
type: "PathExpression";
|
|
data: boolean;
|
|
depth: uint >= 0;
|
|
parts: [ string ];
|
|
original: string;
|
|
}
|
|
```
|
|
|
|
- `data` is true when the given expression is a `@data` reference.
|
|
- `depth` is an integer representation of which context the expression references. `0` represents the current context, `1` would be `../`, etc.
|
|
- `parts` is an array of the names in the path. `foo.bar` would be `['foo', 'bar']`. Scope references, `.`, `..`, and `this` should be omitted from this array.
|
|
- `original` is the path as entered by the user. Separator and scope references are left untouched.
|
|
|
|
|
|
##### Literals
|
|
|
|
```java
|
|
interface Literal <: Expression { }
|
|
|
|
interface StringLiteral <: Literal {
|
|
type: "StringLiteral";
|
|
value: string;
|
|
original: string;
|
|
}
|
|
|
|
interface BooleanLiteral <: Literal {
|
|
type: "BooleanLiteral";
|
|
value: boolean;
|
|
original: boolean;
|
|
}
|
|
|
|
interface NumberLiteral <: Literal {
|
|
type: "NumberLiteral";
|
|
value: number;
|
|
original: number;
|
|
}
|
|
```
|
|
|
|
|
|
### Miscellaneous
|
|
|
|
```java
|
|
interface Hash <: Node {
|
|
type: "Hash";
|
|
pairs: [ HashPair ];
|
|
}
|
|
|
|
interface HashPair <: Node {
|
|
type: "HashPair";
|
|
key: string;
|
|
value: Expression;
|
|
}
|
|
|
|
interface StripFlags {
|
|
left: boolean;
|
|
right: boolean;
|
|
}
|
|
```
|
|
|
|
`StripFlags` are used to signify whitespace control character that may have been entered on a given statement.
|
|
|
|
TODO : Document what the flags mean or drop this from things like Program.
|
|
|
|
## AST Visitor
|
|
|
|
`Handlebars.Visitor` is available as a base class for general interaction with AST structures. This will by default traverse the entire tree and individual methods may be overridden to provide specific responses to particular nodes.
|
|
|
|
Recording all referenced partial names:
|
|
|
|
```javascript
|
|
var Visitor = Handlebars.Visitor;
|
|
|
|
function ImportScanner() {
|
|
this.partials = [];
|
|
}
|
|
ImportScanner.prototype = new Visitor();
|
|
|
|
ImportScanner.prototype.PartialStatement = function(partial) {
|
|
this.partials.push({request: partial.sexpr.original});
|
|
|
|
Visitor.prototype.PartialStatement.call(this, partial);
|
|
};
|
|
|
|
var scanner = new ImportScanner();
|
|
scanner.accept(ast);
|
|
```
|
|
|
|
## JavaScript Compiler
|
|
|
|
The `Handlebars.JavaScriptCompiler` object has a number of methods that may be customized to alter the output of the compiler:
|
|
|
|
```javascript
|
|
function MyCompiler() {
|
|
Handlebars.JavaScriptCompiler.apply(this, arguments);
|
|
}
|
|
MyCompiler.prototype = Object.create(Handlebars.JavaScriptCompiler);
|
|
|
|
MyCompiler.nameLookup = function(parent, name, type) {
|
|
if (type === 'partial') {
|
|
return 'MyPartialList[' + JSON.stringify(name) ']';
|
|
} else {
|
|
return Handlebars.JavaScriptCompiler.prototype.nameLookup.call(this, parent, name, type);
|
|
}
|
|
};
|
|
|
|
var env = Handlebars.create();
|
|
env.JavaScriptCompiler = MyCompiler;
|
|
env.compile('my template');
|
|
```
|