diff options
author | kpdecker <kpdecker@gmail.com> | 2014-11-28 16:55:53 -0600 |
---|---|---|
committer | kpdecker <kpdecker@gmail.com> | 2014-11-28 16:55:53 -0600 |
commit | 95b23095c097447ff4e1059720abfd2132cb9b2d (patch) | |
tree | ae94f80a4d1ff73176818ea24059d7972012350d /docs | |
parent | ffc9fb5007f516350ddeca90640982e4e12503f5 (diff) | |
download | handlebars.js-95b23095c097447ff4e1059720abfd2132cb9b2d.zip handlebars.js-95b23095c097447ff4e1059720abfd2132cb9b2d.tar.gz handlebars.js-95b23095c097447ff4e1059720abfd2132cb9b2d.tar.bz2 |
First crack at compiler API docs
Diffstat (limited to 'docs')
-rw-r--r-- | docs/compiler-api.md | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/docs/compiler-api.md b/docs/compiler-api.md new file mode 100644 index 0000000..7e89b01 --- /dev/null +++ b/docs/compiler-api.md @@ -0,0 +1,224 @@ +# 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'); +``` |