Merge pull request #628 from wycats/es6-modules

Convert code to ES6 modules
This commit is contained in:
Kevin Decker
2013-10-12 14:22:10 -07:00
48 changed files with 777 additions and 3332 deletions
+2 -1
View File
@@ -2,7 +2,8 @@ vendor
.rvmrc
.DS_Store
lib/handlebars/compiler/parser.js
dist
/dist/
/tmp/
node_modules
*.sublime-project
*.sublime-workspace
+2
View File
@@ -30,12 +30,14 @@
"node" : true,
"browser" : true,
"esnext": true,
"boss" : true,
"curly": false,
"debug": false,
"devel": false,
"eqeqeq": false,
"eqnull": true,
"evil": true,
"forin": false,
"immed": false,
+1
View File
@@ -10,6 +10,7 @@ Rakefile
*.gemspec
*.nuspec
bench/*
configurations/*
spec/*
src/*
tasks/*
+2 -2
View File
@@ -3,11 +3,11 @@ node_js:
- "0.8"
- "0.10"
before_script:
before_install:
- npm install -g grunt-cli
script:
- grunt build metrics publish:latest
- grunt --stack build metrics publish:latest
email:
on_failure: change
+82 -45
View File
@@ -1,6 +1,11 @@
var childProcess = require('child_process');
function config(name) {
return require('./configurations/' + name);
}
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
@@ -10,45 +15,49 @@ module.exports = function(grunt) {
force: true
},
files: [
'lib/**/!(parser|browser-prefix|browser-suffix).js'
'lib/**/!(parser).js'
]
},
concat: {
clean: ["dist"],
watch: config('watch') ,
concat: config('concat'),
connect: config('connect'),
transpile: config('transpile'),
packager: {
options: {
banner: '/*!\n\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n@license\n*/\n',
process: function(src, name) {
var match = /\/\/ BEGIN\(BROWSER\)\n((?:.|\n)*)\n\/\/ END\(BROWSER\)/.exec(src);
return '\n// ' + name + '\n' + (match ? match[1] : src);
},
separator: ';'
export: 'Handlebars'
},
dist: {
src: [
'lib/handlebars/browser-prefix.js',
'lib/handlebars/base.js',
'lib/handlebars/compiler/parser.js',
'lib/handlebars/compiler/base.js',
'lib/handlebars/compiler/ast.js',
'lib/handlebars/utils.js',
'lib/handlebars/compiler/compiler.js',
'lib/handlebars/compiler/javascript-compiler.js',
'lib/handlebars/runtime.js',
'lib/handlebars/browser-suffix.js'
],
dest: 'dist/handlebars.js'
},
runtime: {
src: [
'lib/handlebars/browser-prefix.js',
'lib/handlebars/base.js',
'lib/handlebars/utils.js',
'lib/handlebars/runtime.js',
'lib/handlebars/browser-suffix.js'
],
dest: 'dist/handlebars.runtime.js'
global: {
files: [{
cwd: 'lib/',
expand: true,
src: ['handlebars*.js'],
dest: 'dist/'
}]
}
},
requirejs: {
options: {
optimize: "none",
baseUrl: "dist/amd/"
},
dist: {
options: {
name: "handlebars",
out: "dist/handlebars.amd.js"
}
},
runtime: {
options: {
name: "handlebars.runtime",
out: "dist/handlebars.runtime.amd.js"
}
}
},
uglify: {
options: {
mangle: true,
@@ -56,26 +65,55 @@ module.exports = function(grunt) {
preserveComments: 'some'
},
dist: {
src: 'dist/<%= pkg.name %>.js',
dest: 'dist/<%= pkg.name %>.min.js'
},
runtime: {
src: 'dist/<%= pkg.name %>.runtime.js',
dest: 'dist/<%= pkg.name %>.runtime.min.js'
files: [{
cwd: 'dist/',
expand: true,
src: ['handlebars*.js'],
dest: 'dist/',
rename: function(dest, src) {
return dest + src.replace(/\.js$/, '.min.js');
}
}]
}
}
});
// Build a new version of the library
this.registerTask('build', "Builds a distributable version of the current project", [
'jshint',
'clean',
'parser',
'transpile:amd',
'transpile:cjs',
'packager-fork',
'requirejs',
'uglify']);
grunt.registerTask('packager-fork', function() {
// Allows us to run the packager task out of process to work around the multiple
// traceur exec issues
grunt.util.spawn({grunt: true, args: ['packager']}, this.async());
});
// Run a server. This is ideal for running the QUnit tests in the browser.
this.registerTask('server', [
'build',
'tests',
'connect',
'watch']);
// Load tasks from npm
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-es6-module-transpiler');
grunt.loadTasks('tasks');
grunt.task.loadTasks('tasks');
grunt.registerTask('dist-dir', function() {
grunt.file.delete('dist');
grunt.file.mkdir('dist');
});
grunt.registerTask('test', function() {
var done = this.async();
@@ -89,6 +127,5 @@ module.exports = function(grunt) {
});
grunt.registerTask('bench', ['metrics']);
grunt.registerTask('build', ['jshint', 'parser', 'dist-dir', 'concat', 'uglify', 'test']);
grunt.registerTask('default', 'build');
grunt.registerTask('default', ['build', 'test']);
};
+11 -1
View File
@@ -8,7 +8,17 @@ module.exports = function(grunt, callback) {
distSizes = {};
async.each(distFiles, function(file, callback) {
var content = fs.readFileSync('dist/' + file);
var content;
try {
content = fs.readFileSync('dist/' + file);
} catch (err) {
if (err.code === 'EISDIR') {
callback();
return;
} else {
throw err;
}
}
file = file.replace(/\.js/, '').replace(/\./g, '_');
distSizes[file] = content.length;
+1 -1
View File
@@ -3,7 +3,7 @@ var _ = require('underscore'),
module.exports = function(grunt, callback) {
// Deferring to here in case we have a build for parser, etc as part of this grunt exec
var Handlebars = require('../lib/handlebars');
var Handlebars = require('../lib');
var templateSizes = {};
_.each(templates, function(info, template) {
+1 -1
View File
@@ -114,7 +114,7 @@ function makeSuite(bench, name, template, handlebarsOnly) {
module.exports = function(grunt, callback) {
// Deferring load incase we are being run inline with the grunt build
Handlebars = require('../lib/handlebars');
Handlebars = require('../lib');
console.log('Execution Throughput');
runner(grunt, makeSuite, function(times, scaled) {
+6
View File
@@ -0,0 +1,6 @@
module.exports = {
dist: {
src: 'tmp/<%= pkg.barename %>.browser1.js',
dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.js'
}
};
+34
View File
@@ -0,0 +1,34 @@
module.exports = {
options: {
banner: '/*!\n\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n@license\n*/\n',
process: function(src, name) {
var match = /\/\/ BEGIN\(BROWSER\)\n((?:.|\n)*)\n\/\/ END\(BROWSER\)/.exec(src);
return '\n// ' + name + '\n' + (match ? match[1] : src);
}
},
dist: {
src: [
'dist/amd/handlebars/browser-prefix.js',
'dist/amd/handlebars/base.js',
'dist/amd/handlebars/compiler/parser.js',
'dist/amd/handlebars/compiler/base.js',
'dist/amd/handlebars/compiler/ast.js',
'dist/amd/handlebars/utils.js',
'dist/amd/handlebars/compiler/compiler.js',
'dist/amd/handlebars/compiler/javascript-compiler.js',
'dist/amd/handlebars/runtime.js',
'dist/amd/handlebars/browser-suffix.js'
],
dest: 'dist/handlebars.js'
},
runtime: {
src: [
'dist/amd/handlebars/browser-prefix.js',
'dist/amd/handlebars/base.js',
'dist/amd/handlebars/utils.js',
'dist/amd/handlebars/runtime.js',
'dist/amd/handlebars/browser-suffix.js'
],
dest: 'dist/handlebars.runtime.js'
}
};
+8
View File
@@ -0,0 +1,8 @@
module.exports = {
server: {},
options: {
hostname: '0.0.0.0',
port: 8000,
base: '.'
}
};
+34
View File
@@ -0,0 +1,34 @@
module.exports = {
amd: {
type: "amd",
anonymous: true,
files: [{
expand: true,
cwd: 'lib/',
src: '**/!(index).js',
dest: 'dist/amd/'
}]
},
cjs: {
type: 'cjs',
files: [{
expand: true,
cwd: 'lib/',
src: '**/!(index).js',
dest: 'dist/cjs/'
}]
},
globals: {
type: 'globals',
src: ["lib/<%= pkg.barename %>.js", "lib/*/**/*.js"],
dest: "tmp/<%= pkg.barename %>.globals.js"
},
tests: {
type: 'amd',
src: ['test/test_helpers.js', 'test/tests.js', 'test/tests/**/*_test.js'],
dest: 'tmp/tests.amd.js'
}
};
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
files: ['lib/**', 'vendor/*', 'test/**/*'],
tasks: ['build', 'tests']
};
-2310
View File
File diff suppressed because it is too large Load Diff
-402
View File
@@ -1,402 +0,0 @@
/*!
handlebars v1.0.12
Copyright (C) 2011 by Yehuda Katz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@license
*/
// lib/handlebars/browser-prefix.js
(function(undefined) {
var Handlebars = {};
;
// lib/handlebars/base.js
Handlebars.VERSION = "1.0.0";
Handlebars.COMPILER_REVISION = 4;
Handlebars.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) {
return typeof value === 'function';
}
// fallback for older versions of Chrome and Safari
if (isFunction(/x/)) {
isFunction = function(value) {
return typeof value === 'function' && toString.call(value) === '[object Function]';
};
}
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;
}
};
Handlebars.registerPartial = function(name, str) {
if (toString.call(name) === objectType) {
Handlebars.Utils.extend(this.partials, name);
} else {
this.partials[name] = str;
}
};
Handlebars.registerHelper('helperMissing', function(arg) {
if(arguments.length === 2) {
return undefined;
} else {
throw new Error("Missing helper: '" + arg + "'");
}
});
Handlebars.registerHelper('blockHelperMissing', function(context, options) {
var inverse = options.inverse || function() {}, fn = options.fn;
if (isFunction(context)) { context = context.call(this); }
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);
} else {
return inverse(this);
}
} 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,
methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'},
// 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);
}
}
}
};
Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); };
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 (options.data) {
data = Handlebars.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(i === 0){
ret = inverse(this);
}
return ret;
});
Handlebars.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);
}
});
Handlebars.registerHelper('unless', function(conditional, options) {
return Handlebars.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn});
});
Handlebars.registerHelper('with', function(context, options) {
if (isFunction(context)) { context = context.call(this); }
if (!Handlebars.Utils.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);
});
;
// lib/handlebars/utils.js
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 escape = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"'": "&#x27;",
"`": "&#x60;"
};
var badChars = /[&<>"'`]/g;
var possible = /[&<>"'`]/;
var escapeChar = function(chr) {
return escape[chr] || "&amp;";
};
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;
}
}
};
;
// lib/handlebars/runtime.js
function checkRevision(compilerInfo) {
var compilerRevision = compilerInfo && compilerInfo[0] || 1,
currentRevision = Handlebars.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+").";
} 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]+").";
}
}
}
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
};
return function(context, options) {
options = options || {};
var namespace = options.partial ? options : Handlebars,
helpers,
partials;
if (!options.partial) {
helpers = options.helpers;
partials = options.partials;
}
var result = templateSpec.call(
container,
namespace, context,
helpers,
partials,
options.data);
if (!options.partial) {
checkRevision(container.compilerInfo);
}
return result;
};
},
programWithDepth: function(i, fn, data /*, $depth */) {
var args = Array.prototype.slice.call(arguments, 3);
var program = function(context, options) {
options = options || {};
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);
}
}
};
Handlebars.template = Handlebars.VM.template;
;
// lib/handlebars/browser-suffix.js
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);
+20 -35
View File
@@ -1,45 +1,30 @@
/*global Handlebars: true */
import Handlebars from "./handlebars.runtime";
var handlebars = require("./handlebars/base"),
// Each of these augment the Handlebars object. No need to setup here.
// (This is done to easily share code between commonjs and browse envs)
utils = require("./handlebars/utils"),
compiler = require("./handlebars/compiler"),
runtime = require("./handlebars/runtime");
// Compiler imports
module AST from "./handlebars/compiler/ast";
import { parser as Parser, parse } from "./handlebars/compiler/base";
import { Compiler, compile, precompile } from "./handlebars/compiler/compiler";
import JavaScriptCompiler from "./handlebars/compiler/javascript-compiler";
var _create = Handlebars.create;
var create = function() {
var hb = handlebars.create();
var hb = _create();
utils.attach(hb);
compiler.attach(hb);
runtime.attach(hb);
hb.compile = function(input, options) {
return compile(input, options, hb);
};
hb.precompile = precompile;
hb.AST = AST;
hb.Compiler = Compiler;
hb.JavaScriptCompiler = JavaScriptCompiler;
hb.Parser = Parser;
hb.parse = parse;
return hb;
};
var Handlebars = create();
Handlebars = create();
Handlebars.create = create;
module.exports = Handlebars; // instantiate an instance
// Publish a Node.js require() handler for .handlebars and .hbs files
if (require.extensions) {
var extension = function(module, filename) {
var fs = require("fs");
var templateString = fs.readFileSync(filename, "utf8");
module.exports = Handlebars.compile(templateString);
};
require.extensions[".handlebars"] = extension;
require.extensions[".hbs"] = extension;
}
// BEGIN(BROWSER)
// END(BROWSER)
// USAGE:
// var handlebars = require('handlebars');
// var singleton = handlebars.Handlebars,
// local = handlebars.create();
export default Handlebars;
+30
View File
@@ -0,0 +1,30 @@
module base from "./handlebars/base";
// Each of these augment the Handlebars object. No need to setup here.
// (This is done to easily share code between commonjs and browse envs)
import SafeString from "./handlebars/safe-string";
import Exception from "./handlebars/exception";
module Utils from "./handlebars/utils";
module runtime from "./handlebars/runtime";
// For compatibility and usage outside of module systems, make the Handlebars object a namespace
var create = function() {
var hb = new base.HandlebarsEnvironment();
Utils.extend(hb, base);
hb.SafeString = SafeString;
hb.Exception = Exception;
hb.Utils = Utils;
hb.VM = runtime;
hb.template = function(spec) {
return runtime.template(spec, hb);
};
return hb;
};
var Handlebars = create();
Handlebars.create = create;
export default Handlebars;
+135 -125
View File
@@ -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,69 +30,143 @@ 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); }
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);
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 {
return inverse(this);
if (inverse) { fn.not = inverse; }
this.helpers[name] = fn;
}
} else {
return fn(context);
}
});
},
Handlebars.createFrame = function(object) {
var obj = {};
Handlebars.Utils.extend(obj, object);
return obj;
registerPartial: function(name, str) {
if (toString.call(name) === objectType) {
extend(this.partials, name);
} else {
this.partials[name] = str;
}
}
};
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 + "'");
}
});
methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'},
instance.registerHelper('blockHelperMissing', function(context, options) {
var inverse = options.inverse || function() {}, fn = options.fn;
if (isFunction(context)) { context = context.call(this); }
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);
}
});
instance.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 (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(i === 0){
ret = inverse(this);
}
return ret;
});
instance.registerHelper('if', function(conditional, options) {
if (isFunction(conditional)) { conditional = conditional.call(this); }
if (isEmpty(conditional)) {
return options.inverse(this);
} else {
return options.fn(this);
}
});
instance.registerHelper('unless', function(conditional, options) {
return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn});
});
instance.registerHelper('with', function(context, options) {
if (isFunction(context)) { context = context.call(this); }
if (!isEmpty(context)) return options.fn(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 (Handlebars.logger.level <= level) {
var method = Handlebars.logger.methodMap[level];
if (logger.level <= level) {
var method = logger.methodMap[level];
if (typeof console !== 'undefined' && console[method]) {
console[method].call(console, obj);
}
@@ -106,68 +174,10 @@ Handlebars.logger = {
}
};
Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); };
export function log(level, obj) { logger.log(level, obj); }
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 (options.data) {
data = Handlebars.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(i === 0){
ret = inverse(this);
}
return ret;
});
Handlebars.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);
}
});
Handlebars.registerHelper('unless', function(conditional, options) {
return Handlebars.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn});
});
Handlebars.registerHelper('with', function(context, options) {
if (isFunction(context)) { context = context.call(this); }
if (!Handlebars.Utils.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);
});
// END(BROWSER)
return Handlebars;
export var createFrame = function(object) {
var obj = {};
extend(obj, object);
return obj;
};
-2
View File
@@ -1,2 +0,0 @@
(function(undefined) {
var Handlebars = {};
-13
View File
@@ -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);
+30 -39
View File
@@ -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;
};
}
+8 -17
View File
@@ -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; }
if(input.constructor === AST.ProgramNode) { return input; }
Handlebars.Parser.yy = Handlebars.AST;
return Handlebars.Parser.parse(input);
};
// END(BROWSER)
return Handlebars;
};
parser.yy = AST;
return parser.parse(input);
}
+26 -32
View File
@@ -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;
};
}
-18
View File
@@ -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;
};
+9 -21
View File
@@ -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;
+22 -25
View File
@@ -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;
};
+4 -11
View File
@@ -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;
+15
View File
@@ -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;
+120 -106
View File
@@ -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;
// TODO: Remove this line and break up compilePartial
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
};
return function(context, options) {
options = options || {};
var namespace = options.partial ? options : Handlebars,
helpers,
partials;
if (!options.partial) {
helpers = options.helpers;
partials = options.partials;
}
var result = templateSpec.call(
container,
namespace, context,
helpers,
partials,
options.data);
if (!options.partial) {
checkRevision(container.compilerInfo);
}
return result;
};
},
programWithDepth: function(i, fn, data /*, $depth */) {
var args = Array.prototype.slice.call(arguments, 3);
var program = function(context, options) {
options = options || {};
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);
}
export function template(templateSpec, env) {
if (!env) {
throw new Error("No environment passed to template");
}
};
Handlebars.template = Handlebars.VM.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; }
// END(BROWSER)
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");
};
}
return Handlebars;
// 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);
}
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);
if (!options.partial) {
checkRevision(container.compilerInfo);
}
return result;
};
}
export function programWithDepth(i, fn, data /*, $depth */) {
var args = Array.prototype.slice.call(arguments, 3);
var prog = function(context, options) {
options = options || {};
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;
}
export function invokePartial(partial, name, context, helpers, partials, data) {
var options = { partial: true, helpers: helpers, partials: partials, data: data };
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 ""; }
+10
View File
@@ -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;
+34 -66
View File
@@ -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 = {
"&": "&amp;",
@@ -37,50 +14,41 @@ var escape = {
var badChars = /[&<>"'`]/g;
var possible = /[&<>"'`]/;
var escapeChar = function(chr) {
function escapeChar(chr) {
return escape[chr] || "&amp;";
};
}
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;
}
}
+25
View File
@@ -0,0 +1,25 @@
// USAGE:
// var handlebars = require('handlebars');
// var local = handlebars.create();
var handlebars = require('../dist/cjs/handlebars').default;
handlebars.Visitor = require('../dist/cjs/handlebars/compiler/visitor').default;
var printer = require('../dist/cjs/handlebars/compiler/printer');
handlebars.PrintVisitor = printer.PrintVisitor;
handlebars.print = printer.print;
module.exports = handlebars;
// Publish a Node.js require() handler for .handlebars and .hbs files
if (typeof require !== 'undefined' && require.extensions) {
var extension = function(module, filename) {
var fs = require("fs");
var templateString = fs.readFileSync(filename, "utf8");
module.exports = handlebars.compile(templateString);
};
require.extensions[".handlebars"] = extension;
require.extensions[".hbs"] = extension;
}
+23 -7
View File
@@ -1,7 +1,8 @@
{
"name": "handlebars",
"description": "Extension of the Mustache logicless template language",
"barename": "handlebars",
"version": "1.0.12",
"description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration",
"homepage": "http://www.handlebarsjs.com/",
"keywords": [
"handlebars",
@@ -11,13 +12,19 @@
],
"repository": {
"type": "git",
"url": "git://github.com/wycats/handlebars.js.git"
"url": "https://github.com/wycats/handlebars.js.git"
},
"author": "Yehuda Katz",
"license": "BSD",
"readmeFilename": "README.md",
"engines": {
"node": ">=0.4.7"
},
"dependencies": {
"optimist": "~0.3",
"optimist": "~0.3"
},
"optionalDependencies": {
"uglify-js": "~2.3"
},
"devDependencies": {
@@ -27,10 +34,18 @@
"dustjs-linkedin": "~2.0.2",
"eco": "~1.1.0-rc-3",
"grunt": "~0.4.1",
"connect": "~2.7.4",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-clean": "~0.4.1",
"grunt-contrib-connect": "~0.3.0",
"grunt-contrib-jshint": "~0.6.3",
"grunt-contrib-requirejs": "~0.4.1",
"grunt-contrib-uglify": "~0.2.2",
"jison": "~0.3",
"grunt-contrib-watch": "~0.4.4",
"grunt-hang": "~0.1.2",
"grunt-es6-module-transpiler": "joefiorini/grunt-es6-module-transpiler",
"es6-module-packager": "*",
"jison": "~0.3.0",
"keen.io": "0.0.3",
"mocha": "*",
"mustache": "~0.7.2",
@@ -38,12 +53,13 @@
"should": "~1.2.2",
"underscore": "~1.5.1"
},
"main": "lib/handlebars.js",
"main": "lib/index.js",
"bin": {
"handlebars": "bin/handlebars"
},
"scripts": {
"prepublish": "grunt",
"test": "node ./spec/env/runner"
},
"optionalDependencies": {}
}
}
+4 -2
View File
@@ -8,8 +8,10 @@
- [#544](https://github.com/wycats/handlebars.js/issues/544) - Push travis builds to build server ([@fivetanley](https://github.com/fivetanley))
Compatibility notes:
- The client-code has been wrapped in a hybrid AMD/CommonJS loader.
This may cause unexpected issues with different build/loading mechanisms so this change is being made early in the 1.1 lifecycle.
- The project now includes separate artifacts for AMD, CommonJS, and global objects.
- AMD: Users may load the bundled `handlebars.amd.js` or `handlebars.runtime.amd.js` files or load individual modules directly. AMD users should also note that the handlebars object is exposed via the `default` field on the imported object. This [gist](https://gist.github.com/wycats/7417be0dc361a69d5916) provides some discussion of possible compatibility shims.
- CommonJS/Node: Node loading occurs as normal via `require`
- Globals: The `handlebars.js` and `handlebars.runtime.js` files should behave in the same manner as the v1.0.12 / 1.0.0 release.
[Commits](https://github.com/wycats/handlebars.js/compare/v1.0.12...master)
+6
View File
@@ -1,3 +1,9 @@
global.handlebarsEnv = null;
beforeEach(function() {
global.handlebarsEnv = Handlebars.create();
});
describe("basic context", function() {
it("most basic", function() {
shouldCompileTo("{{foo}}", { foo: "foo" }, "foo");
+7 -9
View File
@@ -1,10 +1,5 @@
/*global CompilerContext, shouldCompileTo, compileWithPartials */
describe('builtin helpers', function() {
var originalLog = Handlebars.log;
afterEach(function() {
Handlebars.log = originalLog;
});
describe('#if', function() {
it("if", function() {
var string = "{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!";
@@ -49,6 +44,12 @@ describe('builtin helpers', function() {
});
describe('#each', function() {
beforeEach(function() {
handlebarsEnv.registerHelper('detectDataInsideEach', function(options) {
return options.data && options.data.exclaim;
});
});
it("each", function() {
var string = "{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!";
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
@@ -116,9 +117,6 @@ describe('builtin helpers', function() {
equal(result, 'a!b!c!', 'should output data');
});
Handlebars.registerHelper('detectDataInsideEach', function(options) {
return options.data && options.data.exclaim;
});
});
it("#log", function() {
@@ -127,7 +125,7 @@ describe('builtin helpers', function() {
var hash = { blah: "whee" };
var levelArg, logArg;
Handlebars.log = function(level, arg){ levelArg = level, logArg = arg; };
handlebarsEnv.log = function(level, arg){ levelArg = level, logArg = arg; };
shouldCompileTo(string, hash, "", "log should not display");
equals(1, levelArg, "should call log with 1");
+1 -3
View File
@@ -19,12 +19,10 @@ describe('data', function() {
equals("hello", result, "@foo retrieves template data");
});
var objectCreate = Handlebars.createFrame;
it("deep @foo triggers automatic top-level data", function() {
var template = CompilerContext.compile('{{#let world="world"}}{{#if foo}}{{#if foo}}Hello {{@world}}{{/if}}{{/if}}{{/let}}');
var helpers = objectCreate(Handlebars.helpers);
var helpers = Handlebars.createFrame(handlebarsEnv.helpers);
helpers.let = function(options) {
var frame = Handlebars.createFrame(options.data);
+9 -4
View File
@@ -1,13 +1,18 @@
require('./common');
global.Handlebars = require('../../dist/handlebars');
var _ = require('underscore'),
fs = require('fs'),
vm = require('vm');
global.Handlebars = undefined;
vm.runInThisContext(fs.readFileSync(__dirname + '/../../dist/handlebars.js'), 'dist/handlebars.js');
global.CompilerContext = {
compile: function(template, options) {
var templateSpec = Handlebars.precompile(template, options);
return Handlebars.template(eval('(' + templateSpec + ')'));
var templateSpec = handlebarsEnv.precompile(template, options);
return handlebarsEnv.template(eval('(' + templateSpec + ')'));
},
compileWithPartial: function(template, options) {
return Handlebars.compile(template, options);
return handlebarsEnv.compile(template, options);
}
};
+4 -4
View File
@@ -1,13 +1,13 @@
require('./common');
global.Handlebars = require('../../lib/handlebars');
global.Handlebars = require('../../lib');
global.CompilerContext = {
compile: function(template, options) {
var templateSpec = Handlebars.precompile(template, options);
return Handlebars.template(eval('(' + templateSpec + ')'));
var templateSpec = handlebarsEnv.precompile(template, options);
return handlebarsEnv.template(eval('(' + templateSpec + ')'));
},
compileWithPartial: function(template, options) {
return Handlebars.compile(template, options);
return handlebarsEnv.compile(template, options);
}
};
+2
View File
@@ -6,6 +6,8 @@ var errors = 0,
testDir = path.dirname(__dirname),
grep = process.argv[2];
var files = [ testDir + "/basic.js" ];
var files = fs.readdirSync(testDir)
.filter(function(name) { return (/.*\.js$/).test(name); })
.map(function(name) { return testDir + '/' + name; });
+13 -4
View File
@@ -1,15 +1,24 @@
require('./common');
global.Handlebars = require('../../dist/handlebars.runtime');
var _ = require('underscore'),
fs = require('fs'),
vm = require('vm');
var compiler = require('../../lib/handlebars');
global.Handlebars = undefined;
vm.runInThisContext(fs.readFileSync(__dirname + '/../../dist/handlebars.runtime.js'), 'dist/handlebars.runtime.js');
var compiler = require('../../dist/cjs/handlebars/compiler/compiler');
global.CompilerContext = {
compile: function(template, options) {
var templateSpec = compiler.precompile(template, options);
return Handlebars.template(eval('(' + templateSpec + ')'));
return handlebarsEnv.template(eval('(' + templateSpec + ')'));
},
compileWithPartial: function(template, options) {
return compiler.compile(template, options);
// Hack the compiler on to the environment for these specific tests
handlebarsEnv.compile = function(template, options) {
return compiler.compile(template, options, handlebarsEnv);
};
return handlebarsEnv.compile(template, options);
}
};
+14 -18
View File
@@ -161,7 +161,7 @@ describe('helpers', function() {
});
it("the helper hash should augment the global hash", function() {
Handlebars.registerHelper('test_helper', function() { return 'found it!'; });
handlebarsEnv.registerHelper('test_helper', function() { return 'found it!'; });
shouldCompileTo(
"{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}", [
@@ -173,25 +173,21 @@ describe('helpers', function() {
});
it("Multiple global helper registration", function() {
var helpers = Handlebars.helpers;
try {
Handlebars.helpers = {};
Handlebars.registerHelper({
'if': helpers['if'],
world: function() { return "world!"; },
test_helper: function() { return 'found it!'; }
});
var helpers = handlebarsEnv.helpers;
handlebarsEnv.helpers = {};
shouldCompileTo(
"{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}",
[{cruel: "cruel"}],
"found it! Goodbye cruel world!!");
} finally {
if (helpers) {
Handlebars.helpers = helpers;
}
}
handlebarsEnv.registerHelper({
'if': helpers['if'],
world: function() { return "world!"; },
test_helper: function() { return 'found it!'; }
});
shouldCompileTo(
"{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}",
[{cruel: "cruel"}],
"found it! Goodbye cruel world!!");
});
it("negative number literals work", function() {
var string = 'Message: {{hello -12}}';
var hash = {};
+2 -2
View File
@@ -70,7 +70,7 @@ describe('partials', function() {
});
it("Global Partials", function() {
Handlebars.registerPartial('global_test', '{{another_dude}}');
handlebarsEnv.registerPartial('global_test', '{{another_dude}}');
var string = "Dudes: {{> shared/dude}} {{> global_test}}";
var dude = "{{name}}";
@@ -79,7 +79,7 @@ describe('partials', function() {
});
it("Multiple partial registration", function() {
Handlebars.registerPartial({
handlebarsEnv.registerPartial({
'shared/dude': '{{name}}',
global_test: '{{another_dude}}'
});
+1
View File
@@ -1,4 +1,5 @@
/*global shouldCompileTo */
describe('utils', function() {
describe('#SafeString', function() {
it("constructing a safestring from a string and checking its type", function() {
-1
View File
@@ -1 +0,0 @@
// BEGIN(BROWSER)
+1 -4
View File
@@ -1,4 +1 @@
// END(BROWSER)
module.exports = handlebars;
export default handlebars;
+13
View File
@@ -0,0 +1,13 @@
module.exports = function(grunt) {
grunt.registerMultiTask('packager', 'Transpiles scripts written using ES6 to ES5.', function() {
// Execute in here to prevent traceur private var blowup
var Packager = require('es6-module-packager').default,
fs = require('fs');
var options = this.options();
this.files.forEach(function(file) {
var packager = new Packager(file.src[0], {export: options.export});
fs.writeFileSync(file.dest, packager.toLocals());
});
});
};
+1 -1
View File
@@ -12,7 +12,7 @@ module.exports = function(grunt) {
return;
}
var src = ['src/parser-prefix.js', 'handlebars.js', 'src/parser-suffix.js'].map(grunt.file.read).join('');
var src = ['handlebars.js', 'src/parser-suffix.js'].map(grunt.file.read).join('');
grunt.file.delete('handlebars.js');
grunt.file.write('lib/handlebars/compiler/parser.js', src);