diff options
author | Kevin Decker <kpdecker@gmail.com> | 2013-10-12 14:22:10 -0700 |
---|---|---|
committer | Kevin Decker <kpdecker@gmail.com> | 2013-10-12 14:22:10 -0700 |
commit | 583141de7cb61eb70eaa6b33c25f475f3048071b (patch) | |
tree | 47c419f82f2941fbde5ff5aa33a85b79d6772b4c /lib/handlebars | |
parent | 782aae95d0b430058e2f65b8eba1621453f9055e (diff) | |
parent | 3f96319f103d1e9dc4a6de220d2a9934e00df0b6 (diff) | |
download | handlebars.js-583141de7cb61eb70eaa6b33c25f475f3048071b.zip handlebars.js-583141de7cb61eb70eaa6b33c25f475f3048071b.tar.gz handlebars.js-583141de7cb61eb70eaa6b33c25f475f3048071b.tar.bz2 |
Merge pull request #628 from wycats/es6-modules
Convert code to ES6 modules
Diffstat (limited to 'lib/handlebars')
-rw-r--r-- | lib/handlebars/base.js | 240 | ||||
-rw-r--r-- | lib/handlebars/browser-prefix.js | 2 | ||||
-rw-r--r-- | lib/handlebars/browser-suffix.js | 13 | ||||
-rw-r--r-- | lib/handlebars/compiler/ast.js | 69 | ||||
-rw-r--r-- | lib/handlebars/compiler/base.js | 25 | ||||
-rw-r--r-- | lib/handlebars/compiler/compiler.js | 58 | ||||
-rw-r--r-- | lib/handlebars/compiler/index.js | 18 | ||||
-rw-r--r-- | lib/handlebars/compiler/javascript-compiler.js | 30 | ||||
-rw-r--r-- | lib/handlebars/compiler/printer.js | 47 | ||||
-rw-r--r-- | lib/handlebars/compiler/visitor.js | 15 | ||||
-rw-r--r-- | lib/handlebars/exception.js | 15 | ||||
-rw-r--r-- | lib/handlebars/runtime.js | 214 | ||||
-rw-r--r-- | lib/handlebars/safe-string.js | 10 | ||||
-rw-r--r-- | lib/handlebars/utils.js | 102 |
14 files changed, 398 insertions, 460 deletions
diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index 1decfd2..29c8de8 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -1,32 +1,26 @@ /*jshint eqnull: true */ -module.exports.create = function() { +import { extend, isEmpty } from "./utils"; +import Exception from "./exception"; -var Handlebars = {}; +export var VERSION = "1.0.0"; +export var COMPILER_REVISION = 4; -// BEGIN(BROWSER) - -Handlebars.VERSION = "1.0.0"; -Handlebars.COMPILER_REVISION = 4; - -Handlebars.REVISION_CHANGES = { +export var REVISION_CHANGES = { 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it 2: '== 1.0.0-rc.3', 3: '== 1.0.0-rc.4', 4: '>= 1.0.0' }; -Handlebars.helpers = {}; -Handlebars.partials = {}; - var toString = Object.prototype.toString, objectType = '[object Object]'; // Sourced from lodash // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt -function isFunction(value) { +var isFunction = function(value) { return typeof value === 'function'; -} +}; // fallback for older versions of Chrome and Safari if (isFunction(/x/)) { isFunction = function(value) { @@ -36,138 +30,154 @@ if (isFunction(/x/)) { function isArray(value) { return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; -}; +} -Handlebars.registerHelper = function(name, fn, inverse) { - if (toString.call(name) === objectType) { - if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); } - Handlebars.Utils.extend(this.helpers, name); - } else { - if (inverse) { fn.not = inverse; } - this.helpers[name] = fn; - } -}; +export function HandlebarsEnvironment(helpers, partials) { + this.helpers = helpers || {}; + this.partials = partials || {}; -Handlebars.registerPartial = function(name, str) { - if (toString.call(name) === objectType) { - Handlebars.Utils.extend(this.partials, name); - } else { - this.partials[name] = str; - } -}; + registerDefaultHelpers(this); +} -Handlebars.registerHelper('helperMissing', function(arg) { - if(arguments.length === 2) { - return undefined; - } else { - throw new Error("Missing helper: '" + arg + "'"); - } -}); +HandlebarsEnvironment.prototype = { + constructor: HandlebarsEnvironment, -Handlebars.registerHelper('blockHelperMissing', function(context, options) { - var inverse = options.inverse || function() {}, fn = options.fn; + logger: logger, + log: log, - if (isFunction(context)) { context = context.call(this); } + registerHelper: function(name, fn, inverse) { + if (toString.call(name) === objectType) { + if (inverse || fn) { throw new Exception('Arg not supported with multiple helpers'); } + extend(this.helpers, name); + } else { + if (inverse) { fn.not = inverse; } + this.helpers[name] = fn; + } + }, - if(context === true) { - return fn(this); - } else if(context === false || context == null) { - return inverse(this); - } else if (isArray(context)) { - if(context.length > 0) { - return Handlebars.helpers.each(context, options); + registerPartial: function(name, str) { + if (toString.call(name) === objectType) { + extend(this.partials, name); } else { - return inverse(this); + this.partials[name] = str; } - } else { - return fn(context); } -}); - -Handlebars.createFrame = function(object) { - var obj = {}; - Handlebars.Utils.extend(obj, object); - return obj; }; -Handlebars.logger = { - DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, +function registerDefaultHelpers(instance) { + instance.registerHelper('helperMissing', function(arg) { + if(arguments.length === 2) { + return undefined; + } else { + throw new Error("Missing helper: '" + arg + "'"); + } + }); + + instance.registerHelper('blockHelperMissing', function(context, options) { + var inverse = options.inverse || function() {}, fn = options.fn; - methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'}, + if (isFunction(context)) { context = context.call(this); } - // can be overridden in the host environment - log: function(level, obj) { - if (Handlebars.logger.level <= level) { - var method = Handlebars.logger.methodMap[level]; - if (typeof console !== 'undefined' && console[method]) { - console[method].call(console, obj); + if(context === true) { + return fn(this); + } else if(context === false || context == null) { + return inverse(this); + } else if (isArray(context)) { + if(context.length > 0) { + return instance.helpers.each(context, options); + } else { + return inverse(this); } + } else { + return fn(context); } - } -}; + }); -Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); }; + instance.registerHelper('each', function(context, options) { + var fn = options.fn, inverse = options.inverse; + var i = 0, ret = "", data; -Handlebars.registerHelper('each', function(context, options) { - var fn = options.fn, inverse = options.inverse; - var i = 0, ret = "", data; + if (isFunction(context)) { context = context.call(this); } - if (isFunction(context)) { context = context.call(this); } - - if (options.data) { - data = Handlebars.createFrame(options.data); - } + if (options.data) { + data = createFrame(options.data); + } - if(context && typeof context === 'object') { - if (isArray(context)) { - for(var j = context.length; i<j; i++) { - if (data) { data.index = i; } - ret = ret + fn(context[i], { data: data }); - } - } else { - for(var key in context) { - if(context.hasOwnProperty(key)) { - if(data) { data.key = key; } - ret = ret + fn(context[key], {data: data}); - i++; + if(context && typeof context === 'object') { + if (isArray(context)) { + for(var j = context.length; i<j; i++) { + if (data) { data.index = i; } + ret = ret + fn(context[i], { data: data }); + } + } else { + for(var key in context) { + if(context.hasOwnProperty(key)) { + if(data) { data.key = key; } + ret = ret + fn(context[key], {data: data}); + i++; + } } } } - } - if(i === 0){ - ret = inverse(this); - } + if(i === 0){ + ret = inverse(this); + } - return ret; -}); + return ret; + }); -Handlebars.registerHelper('if', function(conditional, options) { - if (isFunction(conditional)) { conditional = conditional.call(this); } + instance.registerHelper('if', function(conditional, options) { + if (isFunction(conditional)) { conditional = conditional.call(this); } - if(Handlebars.Utils.isEmpty(conditional)) { - return options.inverse(this); - } else { - return options.fn(this); - } -}); + if (isEmpty(conditional)) { + return options.inverse(this); + } else { + return options.fn(this); + } + }); -Handlebars.registerHelper('unless', function(conditional, options) { - return Handlebars.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn}); -}); + instance.registerHelper('unless', function(conditional, options) { + return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn}); + }); -Handlebars.registerHelper('with', function(context, options) { - if (isFunction(context)) { context = context.call(this); } + instance.registerHelper('with', function(context, options) { + if (isFunction(context)) { context = context.call(this); } - if (!Handlebars.Utils.isEmpty(context)) return options.fn(context); -}); + if (!isEmpty(context)) return options.fn(context); + }); -Handlebars.registerHelper('log', function(context, options) { - var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1; - Handlebars.log(level, context); -}); + instance.registerHelper('log', function(context, options) { + var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1; + instance.log(level, context); + }); +} + +export var logger = { + methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' }, + + // State enum + DEBUG: 0, + INFO: 1, + WARN: 2, + ERROR: 3, + level: 3, + + // can be overridden in the host environment + log: function(level, obj) { + if (logger.level <= level) { + var method = logger.methodMap[level]; + if (typeof console !== 'undefined' && console[method]) { + console[method].call(console, obj); + } + } + } +}; -// END(BROWSER) +export function log(level, obj) { logger.log(level, obj); } -return Handlebars; +export var createFrame = function(object) { + var obj = {}; + extend(obj, object); + return obj; }; diff --git a/lib/handlebars/browser-prefix.js b/lib/handlebars/browser-prefix.js deleted file mode 100644 index a8f1722..0000000 --- a/lib/handlebars/browser-prefix.js +++ /dev/null @@ -1,2 +0,0 @@ -(function(undefined) { - var Handlebars = {}; diff --git a/lib/handlebars/browser-suffix.js b/lib/handlebars/browser-suffix.js deleted file mode 100644 index d357c72..0000000 --- a/lib/handlebars/browser-suffix.js +++ /dev/null @@ -1,13 +0,0 @@ - if (typeof module === 'object' && module.exports) { - // CommonJS - module.exports = Handlebars; - - } else if (typeof define === "function" && define.amd) { - // AMD modules - define(function() { return Handlebars; }); - - } else { - // other, i.e. browser - this.Handlebars = Handlebars; - } -}).call(this); diff --git a/lib/handlebars/compiler/ast.js b/lib/handlebars/compiler/ast.js index 567e297..336492d 100644 --- a/lib/handlebars/compiler/ast.js +++ b/lib/handlebars/compiler/ast.js @@ -1,15 +1,12 @@ -exports.attach = function(Handlebars) { +import Exception from "../exception"; -// BEGIN(BROWSER) -Handlebars.AST = {}; - -Handlebars.AST.ProgramNode = function(statements, inverse) { +export function ProgramNode(statements, inverse) { this.type = "program"; this.statements = statements; - if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); } -}; + if(inverse) { this.inverse = new ProgramNode(inverse); } +} -Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) { +export function MustacheNode(rawParams, hash, unescaped) { this.type = "mustache"; this.escaped = !unescaped; this.hash = hash; @@ -29,17 +26,17 @@ Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) { // if a mustache is an eligible helper but not a definite // helper, it is ambiguous, and will be resolved in a later // pass or at runtime. -}; +} -Handlebars.AST.PartialNode = function(partialName, context) { +export function PartialNode(partialName, context) { this.type = "partial"; this.partialName = partialName; this.context = context; -}; +} -Handlebars.AST.BlockNode = function(mustache, program, inverse, close) { +export function BlockNode(mustache, program, inverse, close) { if(mustache.id.original !== close.original) { - throw new Handlebars.Exception(mustache.id.original + " doesn't match " + close.original); + throw new Exception(mustache.id.original + " doesn't match " + close.original); } this.type = "block"; @@ -50,19 +47,19 @@ Handlebars.AST.BlockNode = function(mustache, program, inverse, close) { if (this.inverse && !this.program) { this.isInverse = true; } -}; +} -Handlebars.AST.ContentNode = function(string) { +export function ContentNode(string) { this.type = "content"; this.string = string; -}; +} -Handlebars.AST.HashNode = function(pairs) { +export function HashNode(pairs) { this.type = "hash"; this.pairs = pairs; -}; +} -Handlebars.AST.IdNode = function(parts) { +export function IdNode(parts) { this.type = "ID"; var original = "", @@ -74,7 +71,7 @@ Handlebars.AST.IdNode = function(parts) { original += (parts[i].separator || '') + part; if (part === ".." || part === "." || part === "this") { - if (dig.length > 0) { throw new Handlebars.Exception("Invalid path: " + original); } + if (dig.length > 0) { throw new Exception("Invalid path: " + original); } else if (part === "..") { depth++; } else { this.isScoped = true; } } @@ -91,45 +88,39 @@ Handlebars.AST.IdNode = function(parts) { this.isSimple = parts.length === 1 && !this.isScoped && depth === 0; this.stringModeValue = this.string; -}; +} -Handlebars.AST.PartialNameNode = function(name) { +export function PartialNameNode(name) { this.type = "PARTIAL_NAME"; this.name = name.original; -}; +} -Handlebars.AST.DataNode = function(id) { +export function DataNode(id) { this.type = "DATA"; this.id = id; -}; +} -Handlebars.AST.StringNode = function(string) { +export function StringNode(string) { this.type = "STRING"; this.original = this.string = this.stringModeValue = string; -}; +} -Handlebars.AST.IntegerNode = function(integer) { +export function IntegerNode(integer) { this.type = "INTEGER"; this.original = this.integer = integer; this.stringModeValue = Number(integer); -}; +} -Handlebars.AST.BooleanNode = function(bool) { +export function BooleanNode(bool) { this.type = "BOOLEAN"; this.bool = bool; this.stringModeValue = bool === "true"; -}; +} -Handlebars.AST.CommentNode = function(comment) { +export function CommentNode(comment) { this.type = "comment"; this.comment = comment; -}; - -// END(BROWSER) - -return Handlebars; -}; - +} diff --git a/lib/handlebars/compiler/base.js b/lib/handlebars/compiler/base.js index 7594451..d6cb06e 100644 --- a/lib/handlebars/compiler/base.js +++ b/lib/handlebars/compiler/base.js @@ -1,21 +1,12 @@ -var handlebars = require("./parser"); +import parser from "./parser"; +module AST from "./ast"; -exports.attach = function(Handlebars) { - -// BEGIN(BROWSER) - -Handlebars.Parser = handlebars; - -Handlebars.parse = function(input) { +export { parser }; +export function parse(input) { // Just return if an already-compile AST was passed in. - if(input.constructor === Handlebars.AST.ProgramNode) { return input; } - - Handlebars.Parser.yy = Handlebars.AST; - return Handlebars.Parser.parse(input); -}; - -// END(BROWSER) + if(input.constructor === AST.ProgramNode) { return input; } -return Handlebars; -}; + parser.yy = AST; + return parser.parse(input); +} diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index 98e12b1..50195e3 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -1,13 +1,9 @@ -var compilerbase = require("./base"); +import Exception from "../exception"; +import { parse } from "./base"; +import JavaScriptCompiler from "./javascript-compiler"; +module AST from "./ast"; -exports.attach = function(Handlebars) { - -compilerbase.attach(Handlebars); - -// BEGIN(BROWSER) - -/*jshint eqnull:true*/ -var Compiler = Handlebars.Compiler = function() {}; +export function Compiler() {} // the foundHelper register will disambiguate helper lookup from finding a // function in a context. This is necessary for mustache compatibility, which @@ -40,6 +36,7 @@ Compiler.prototype = { return out.join("\n"); }, + equals: function(other) { var len = this.opcodes.length; if (other.opcodes.length !== len) { @@ -301,7 +298,7 @@ Compiler.prototype = { DATA: function(data) { this.options.data = true; if (data.id.isScoped || data.id.depth) { - throw new Handlebars.Exception('Scoped data references are not supported: ' + data.original); + throw new Exception('Scoped data references are not supported: ' + data.original); } this.opcode('lookupData'); @@ -415,49 +412,46 @@ Compiler.prototype = { } }; -Handlebars.precompile = function(input, options) { - if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { - throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input); +export function precompile(input, options) { + if (input == null || (typeof input !== 'string' && input.constructor !== AST.ProgramNode)) { + throw new Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input); } options = options || {}; if (!('data' in options)) { options.data = true; } - var ast = Handlebars.parse(input); + + var ast = parse(input); var environment = new Compiler().compile(ast, options); - return new Handlebars.JavaScriptCompiler().compile(environment, options); -}; + return new JavaScriptCompiler().compile(environment, options); +} -Handlebars.compile = function(input, options) { - if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { - throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input); +export function compile(input, options, env) { + if (input == null || (typeof input !== 'string' && input.constructor !== AST.ProgramNode)) { + throw new Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input); } options = options || {}; + if (!('data' in options)) { options.data = true; } + var compiled; - function compile() { - var ast = Handlebars.parse(input); + + function compileInput() { + var ast = parse(input); var environment = new Compiler().compile(ast, options); - var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true); - return Handlebars.template(templateSpec); + var templateSpec = new JavaScriptCompiler().compile(environment, options, undefined, true); + return env.template(templateSpec); } // Template is only compiled on first use and cached after that point. return function(context, options) { if (!compiled) { - compiled = compile(); + compiled = compileInput(); } return compiled.call(this, context, options); }; -}; - - -// END(BROWSER) - -return Handlebars; - -}; +} diff --git a/lib/handlebars/compiler/index.js b/lib/handlebars/compiler/index.js deleted file mode 100644 index 0cc5c01..0000000 --- a/lib/handlebars/compiler/index.js +++ /dev/null @@ -1,18 +0,0 @@ -// Each of these module will augment the Handlebars object as it loads. No need to perform addition operations -module.exports.attach = function(Handlebars) { - -var visitor = require("./visitor"), - printer = require("./printer"), - ast = require("./ast"), - compiler = require("./compiler"), - javascriptCompiler = require("./javascript-compiler"); - -visitor.attach(Handlebars); -printer.attach(Handlebars); -ast.attach(Handlebars); -compiler.attach(Handlebars); -javascriptCompiler.attach(Handlebars); - -return Handlebars; - -}; diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index 0bb1816..a81a99c 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -1,18 +1,10 @@ -var compilerbase = require("./base"); +import { COMPILER_REVISION, REVISION_CHANGES, log } from "../base"; -exports.attach = function(Handlebars) { - -compilerbase.attach(Handlebars); - -// BEGIN(BROWSER) -/*jshint eqnull:true*/ - -var Literal = function(value) { +function Literal(value) { this.value = value; -}; - +} -var JavaScriptCompiler = Handlebars.JavaScriptCompiler = function() {}; +function JavaScriptCompiler() {} JavaScriptCompiler.prototype = { // PUBLIC API: You can override these methods in a subclass to provide @@ -51,7 +43,7 @@ JavaScriptCompiler.prototype = { this.environment = environment; this.options = options || {}; - Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n"); + log('debug', this.environment.disassemble() + "\n\n"); this.name = this.environment.name; this.isChild = !!context; @@ -162,8 +154,8 @@ JavaScriptCompiler.prototype = { var source = this.mergeSource(); if (!this.isChild) { - var revision = Handlebars.COMPILER_REVISION, - versions = Handlebars.REVISION_CHANGES[revision]; + var revision = COMPILER_REVISION, + versions = REVISION_CHANGES[revision]; source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source; } @@ -173,7 +165,7 @@ JavaScriptCompiler.prototype = { return Function.apply(this, params); } else { var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}'; - Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n"); + log('debug', functionSource + "\n\n"); return functionSource; } }, @@ -849,8 +841,4 @@ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) { return false; }; -// END(BROWSER) - -return Handlebars; - -}; +export default JavaScriptCompiler; diff --git a/lib/handlebars/compiler/printer.js b/lib/handlebars/compiler/printer.js index d9eb7a5..a35cdf4 100644 --- a/lib/handlebars/compiler/printer.js +++ b/lib/handlebars/compiler/printer.js @@ -1,15 +1,16 @@ -exports.attach = function(Handlebars) { +import Visitor from "./visitor"; -// BEGIN(BROWSER) +export function print(ast) { + return new PrintVisitor().accept(ast); +} -Handlebars.print = function(ast) { - return new Handlebars.PrintVisitor().accept(ast); -}; +export function PrintVisitor() { + this.padding = 0; +} -Handlebars.PrintVisitor = function() { this.padding = 0; }; -Handlebars.PrintVisitor.prototype = new Handlebars.Visitor(); +PrintVisitor.prototype = new Visitor(); -Handlebars.PrintVisitor.prototype.pad = function(string, newline) { +PrintVisitor.prototype.pad = function(string, newline) { var out = ""; for(var i=0,l=this.padding; i<l; i++) { @@ -22,7 +23,7 @@ Handlebars.PrintVisitor.prototype.pad = function(string, newline) { return out; }; -Handlebars.PrintVisitor.prototype.program = function(program) { +PrintVisitor.prototype.program = function(program) { var out = "", statements = program.statements, inverse = program.inverse, @@ -37,7 +38,7 @@ Handlebars.PrintVisitor.prototype.program = function(program) { return out; }; -Handlebars.PrintVisitor.prototype.block = function(block) { +PrintVisitor.prototype.block = function(block) { var out = ""; out = out + this.pad("BLOCK:"); @@ -62,7 +63,7 @@ Handlebars.PrintVisitor.prototype.block = function(block) { return out; }; -Handlebars.PrintVisitor.prototype.mustache = function(mustache) { +PrintVisitor.prototype.mustache = function(mustache) { var params = mustache.params, paramStrings = [], hash; for(var i=0, l=params.length; i<l; i++) { @@ -76,13 +77,13 @@ Handlebars.PrintVisitor.prototype.mustache = function(mustache) { return this.pad("{{ " + this.accept(mustache.id) + " " + params + hash + " }}"); }; -Handlebars.PrintVisitor.prototype.partial = function(partial) { +PrintVisitor.prototype.partial = function(partial) { var content = this.accept(partial.partialName); if(partial.context) { content = content + " " + this.accept(partial.context); } return this.pad("{{> " + content + " }}"); }; -Handlebars.PrintVisitor.prototype.hash = function(hash) { +PrintVisitor.prototype.hash = function(hash) { var pairs = hash.pairs; var joinedPairs = [], left, right; @@ -95,19 +96,19 @@ Handlebars.PrintVisitor.prototype.hash = function(hash) { return "HASH{" + joinedPairs.join(", ") + "}"; }; -Handlebars.PrintVisitor.prototype.STRING = function(string) { +PrintVisitor.prototype.STRING = function(string) { return '"' + string.string + '"'; }; -Handlebars.PrintVisitor.prototype.INTEGER = function(integer) { +PrintVisitor.prototype.INTEGER = function(integer) { return "INTEGER{" + integer.integer + "}"; }; -Handlebars.PrintVisitor.prototype.BOOLEAN = function(bool) { +PrintVisitor.prototype.BOOLEAN = function(bool) { return "BOOLEAN{" + bool.bool + "}"; }; -Handlebars.PrintVisitor.prototype.ID = function(id) { +PrintVisitor.prototype.ID = function(id) { var path = id.parts.join("/"); if(id.parts.length > 1) { return "PATH:" + path; @@ -116,23 +117,19 @@ Handlebars.PrintVisitor.prototype.ID = function(id) { } }; -Handlebars.PrintVisitor.prototype.PARTIAL_NAME = function(partialName) { +PrintVisitor.prototype.PARTIAL_NAME = function(partialName) { return "PARTIAL:" + partialName.name; }; -Handlebars.PrintVisitor.prototype.DATA = function(data) { +PrintVisitor.prototype.DATA = function(data) { return "@" + this.accept(data.id); }; -Handlebars.PrintVisitor.prototype.content = function(content) { +PrintVisitor.prototype.content = function(content) { return this.pad("CONTENT[ '" + content.string + "' ]"); }; -Handlebars.PrintVisitor.prototype.comment = function(comment) { +PrintVisitor.prototype.comment = function(comment) { return this.pad("{{! '" + comment.comment + "' }}"); }; -// END(BROWSER) - -return Handlebars; -}; diff --git a/lib/handlebars/compiler/visitor.js b/lib/handlebars/compiler/visitor.js index 5d07314..6a0373e 100644 --- a/lib/handlebars/compiler/visitor.js +++ b/lib/handlebars/compiler/visitor.js @@ -1,18 +1,11 @@ -exports.attach = function(Handlebars) { +function Visitor() {} -// BEGIN(BROWSER) +Visitor.prototype = { + constructor: Visitor, -Handlebars.Visitor = function() {}; - -Handlebars.Visitor.prototype = { accept: function(object) { return this[object.type](object); } }; -// END(BROWSER) - -return Handlebars; -}; - - +export default Visitor; diff --git a/lib/handlebars/exception.js b/lib/handlebars/exception.js new file mode 100644 index 0000000..6de9cfd --- /dev/null +++ b/lib/handlebars/exception.js @@ -0,0 +1,15 @@ + +var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; + +function Exception(/* message */) { + var tmp = Error.prototype.constructor.apply(this, arguments); + + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } +} + +Exception.prototype = new Error(); + +export default Exception; diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index 81e8aef..57a830b 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -1,124 +1,138 @@ -exports.attach = function(Handlebars) { - -// BEGIN(BROWSER) +import Exception from "./exception"; +import { escapeExpression, extend } from "./utils"; +import { COMPILER_REVISION, REVISION_CHANGES } from "./base"; function checkRevision(compilerInfo) { var compilerRevision = compilerInfo && compilerInfo[0] || 1, - currentRevision = Handlebars.COMPILER_REVISION; + currentRevision = COMPILER_REVISION; if (compilerRevision !== currentRevision) { if (compilerRevision < currentRevision) { - var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision], - compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision]; - throw "Template was precompiled with an older version of Handlebars than the current runtime. "+ - "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."; + var runtimeVersions = REVISION_CHANGES[currentRevision], + compilerVersions = REVISION_CHANGES[compilerRevision]; + throw new Error("Template was precompiled with an older version of Handlebars than the current runtime. "+ + "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."); } else { // Use the embedded version info since the runtime doesn't know about this revision yet - throw "Template was precompiled with a newer version of Handlebars than the current runtime. "+ - "Please update your runtime to a newer version ("+compilerInfo[1]+")."; + throw new Error("Template was precompiled with a newer version of Handlebars than the current runtime. "+ + "Please update your runtime to a newer version ("+compilerInfo[1]+")."); } } } -Handlebars.VM = { - template: function(templateSpec) { - // Just add water - var container = { - escapeExpression: Handlebars.Utils.escapeExpression, - invokePartial: Handlebars.VM.invokePartial, - programs: [], - program: function(i, fn, data) { - var programWrapper = this.programs[i]; - if(data) { - programWrapper = Handlebars.VM.program(i, fn, data); - } else if (!programWrapper) { - programWrapper = this.programs[i] = Handlebars.VM.program(i, fn); - } - return programWrapper; - }, - merge: function(param, common) { - var ret = param || common; - - if (param && common && (param !== common)) { - ret = {}; - Handlebars.Utils.extend(ret, common); - Handlebars.Utils.extend(ret, param); - } - return ret; - }, - programWithDepth: Handlebars.VM.programWithDepth, - noop: Handlebars.VM.noop, - compilerInfo: null - }; +// TODO: Remove this line and break up compilePartial - return function(context, options) { - options = options || {}; - var namespace = options.partial ? options : Handlebars, - helpers, - partials; +export function template(templateSpec, env) { + if (!env) { + throw new Error("No environment passed to template"); + } + + var invokePartialWrapper; + if (env.compile) { + invokePartialWrapper = function(partial, name, context, helpers, partials, data) { + // TODO : Check this for all inputs and the options handling (partial flag, etc). This feels + // like there should be a common exec path + var result = invokePartial.apply(this, arguments); + if (result) { return result; } + + var options = { helpers: helpers, partials: partials, data: data }; + partials[name] = env.compile(partial, { data: data !== undefined }, env); + return partials[name](context, options); + }; + } else { + invokePartialWrapper = function(partial, name /* , context, helpers, partials, data */) { + var result = invokePartial.apply(this, arguments); + if (result) { return result; } + throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); + }; + } - if (!options.partial) { - helpers = options.helpers; - partials = options.partials; + // Just add water + var container = { + escapeExpression: escapeExpression, + invokePartial: invokePartialWrapper, + programs: [], + program: function(i, fn, data) { + var programWrapper = this.programs[i]; + if(data) { + programWrapper = program(i, fn, data); + } else if (!programWrapper) { + programWrapper = this.programs[i] = program(i, fn); } - var result = templateSpec.call( - container, - namespace, context, - helpers, - partials, - options.data); - - if (!options.partial) { - checkRevision(container.compilerInfo); + return programWrapper; + }, + merge: function(param, common) { + var ret = param || common; + + if (param && common && (param !== common)) { + ret = {}; + extend(ret, common); + extend(ret, param); } + return ret; + }, + programWithDepth: programWithDepth, + noop: noop, + compilerInfo: null + }; + + return function(context, options) { + options = options || {}; + var namespace = options.partial ? options : env, + helpers, + partials; + + if (!options.partial) { + helpers = options.helpers; + partials = options.partials; + } + var result = templateSpec.call( + container, + namespace, context, + helpers, + partials, + options.data); - return result; - }; - }, + if (!options.partial) { + checkRevision(container.compilerInfo); + } - programWithDepth: function(i, fn, data /*, $depth */) { - var args = Array.prototype.slice.call(arguments, 3); + return result; + }; +} - var program = function(context, options) { - options = options || {}; +export function programWithDepth(i, fn, data /*, $depth */) { + var args = Array.prototype.slice.call(arguments, 3); - return fn.apply(this, [context, options.data || data].concat(args)); - }; - program.program = i; - program.depth = args.length; - return program; - }, - program: function(i, fn, data) { - var program = function(context, options) { - options = options || {}; - - return fn(context, options.data || data); - }; - program.program = i; - program.depth = 0; - return program; - }, - noop: function() { return ""; }, - invokePartial: function(partial, name, context, helpers, partials, data) { - var options = { partial: true, helpers: helpers, partials: partials, data: data }; - - if(partial === undefined) { - throw new Handlebars.Exception("The partial " + name + " could not be found"); - } else if(partial instanceof Function) { - return partial(context, options); - } else if (!Handlebars.compile) { - throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); - } else { - partials[name] = Handlebars.compile(partial, {data: data !== undefined}); - return partials[name](context, options); - } - } -}; + var prog = function(context, options) { + options = options || {}; -Handlebars.template = Handlebars.VM.template; + return fn.apply(this, [context, options.data || data].concat(args)); + }; + prog.program = i; + prog.depth = args.length; + return prog; +} + +export function program(i, fn, data) { + var prog = function(context, options) { + options = options || {}; + + return fn(context, options.data || data); + }; + prog.program = i; + prog.depth = 0; + return prog; +} -// END(BROWSER) +export function invokePartial(partial, name, context, helpers, partials, data) { + var options = { partial: true, helpers: helpers, partials: partials, data: data }; -return Handlebars; + if(partial === undefined) { + throw new Exception("The partial " + name + " could not be found"); + } else if(partial instanceof Function) { + return partial(context, options); + } +} -}; +export function noop() { return ""; } diff --git a/lib/handlebars/safe-string.js b/lib/handlebars/safe-string.js new file mode 100644 index 0000000..2ae49aa --- /dev/null +++ b/lib/handlebars/safe-string.js @@ -0,0 +1,10 @@ +// Build out our basic SafeString type +function SafeString(string) { + this.string = string; +} + +SafeString.prototype.toString = function() { + return "" + this.string; +}; + +export default SafeString; diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js index 59947ca..998c9ca 100644 --- a/lib/handlebars/utils.js +++ b/lib/handlebars/utils.js @@ -1,29 +1,6 @@ -exports.attach = function(Handlebars) { +import SafeString from "./safe-string"; -var toString = Object.prototype.toString, - isArray = Array.isArray; - -// BEGIN(BROWSER) - -var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; - -Handlebars.Exception = function(message) { - var tmp = Error.prototype.constructor.apply(this, arguments); - - // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. - for (var idx = 0; idx < errorProps.length; idx++) { - this[errorProps[idx]] = tmp[errorProps[idx]]; - } -}; -Handlebars.Exception.prototype = new Error(); - -// Build out our basic SafeString type -Handlebars.SafeString = function(string) { - this.string = string; -}; -Handlebars.SafeString.prototype.toString = function() { - return "" + this.string; -}; +var isArray = Array.isArray; var escape = { "&": "&", @@ -37,50 +14,41 @@ var escape = { var badChars = /[&<>"'`]/g; var possible = /[&<>"'`]/; -var escapeChar = function(chr) { +function escapeChar(chr) { return escape[chr] || "&"; -}; - -Handlebars.Utils = { - extend: function(obj, value) { - for(var key in value) { - if(value.hasOwnProperty(key)) { - obj[key] = value[key]; - } - } - }, - - escapeExpression: function(string) { - /*jshint eqnull: true */ - - // don't escape SafeStrings, since they're already safe - if (string instanceof Handlebars.SafeString) { - return string.toString(); - } else if (!string && string !== 0) { - return ""; - } - - // Force a string conversion as this will be done by the append regardless and - // the regex test will do this transparently behind the scenes, causing issues if - // an object's to string has escaped characters in it. - string = "" + string; - - if(!possible.test(string)) { return string; } - return string.replace(badChars, escapeChar); - }, +} - isEmpty: function(value) { - if (!value && value !== 0) { - return true; - } else if (isArray(value) && value.length === 0) { - return true; - } else { - return false; +export function extend(obj, value) { + for(var key in value) { + if(value.hasOwnProperty(key)) { + obj[key] = value[key]; } } -}; - -// END(BROWSER) +} + +export function escapeExpression(string) { + // don't escape SafeStrings, since they're already safe + if (string instanceof SafeString) { + return string.toString(); + } else if (!string && string !== 0) { + return ""; + } -return Handlebars; -}; + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = "" + string; + + if(!possible.test(string)) { return string; } + return string.replace(badChars, escapeChar); +} + +export function isEmpty(value) { + if (!value && value !== 0) { + return true; + } else if (isArray(value) && value.length === 0) { + return true; + } else { + return false; + } +} |