@@ -0,0 +1,186 @@
|
||||
{
|
||||
"globals": {
|
||||
"self": false
|
||||
},
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"ecmaFeatures": {
|
||||
"modules": true
|
||||
},
|
||||
"rules": {
|
||||
// Possible Errors //
|
||||
//-----------------//
|
||||
|
||||
"comma-dangle": [2, "never"],
|
||||
"no-cond-assign": [2, "except-parens"],
|
||||
|
||||
// Allow for debugging
|
||||
"no-console": 1,
|
||||
|
||||
"no-constant-condition": 2,
|
||||
"no-control-regex": 2,
|
||||
|
||||
// Allow for debugging
|
||||
"no-debugger": 1,
|
||||
|
||||
"no-dupe-args": 2,
|
||||
"no-dupe-keys": 2,
|
||||
"no-duplicate-case": 2,
|
||||
"no-empty": 2,
|
||||
"no-empty-class": 2,
|
||||
"no-ex-assign": 2,
|
||||
"no-extra-boolean-cast": 2,
|
||||
"no-extra-parens": 0,
|
||||
"no-extra-semi": 2,
|
||||
"no-func-assign": 2,
|
||||
|
||||
// Stylistic... might consider disallowing in the future
|
||||
"no-inner-declarations": 0,
|
||||
|
||||
"no-invalid-regexp": 2,
|
||||
"no-irregular-whitespace": 2,
|
||||
"no-negated-in-lhs": 2,
|
||||
"no-obj-calls": 2,
|
||||
"no-regex-spaces": 2,
|
||||
"no-reserved-keys": 2, // Important for IE
|
||||
"no-sparse-arrays": 0,
|
||||
|
||||
// Optimizer and coverage will handle/highlight this and can be useful for debugging
|
||||
"no-unreachable": 1,
|
||||
|
||||
"use-isnan": 2,
|
||||
"valid-jsdoc": 0,
|
||||
"valid-typeof": 2,
|
||||
|
||||
|
||||
// Best Practices //
|
||||
//----------------//
|
||||
"block-scoped-var": 0,
|
||||
"complexity": 0,
|
||||
"consistent-return": 0,
|
||||
"curly": 2,
|
||||
"default-case": 1,
|
||||
"dot-notation": [2, {"allowKeywords": false}],
|
||||
"eqeqeq": 0,
|
||||
"guard-for-in": 1,
|
||||
"no-alert": 2,
|
||||
"no-caller": 2,
|
||||
"no-div-regex": 1,
|
||||
"no-else-return": 0,
|
||||
"no-empty-label": 2,
|
||||
"no-eq-null": 0,
|
||||
"no-eval": 2,
|
||||
"no-extend-native": 2,
|
||||
"no-extra-bind": 2,
|
||||
"no-fallthrough": 2,
|
||||
"no-floating-decimal": 2,
|
||||
"no-implied-eval": 2,
|
||||
"no-iterator": 2,
|
||||
"no-labels": 2,
|
||||
"no-lone-blocks": 2,
|
||||
"no-loop-func": 2,
|
||||
"no-multi-spaces": 2,
|
||||
"no-multi-str": 1,
|
||||
"no-native-reassign": 2,
|
||||
"no-new": 2,
|
||||
"no-new-func": 2,
|
||||
"no-new-wrappers": 2,
|
||||
"no-octal": 2,
|
||||
"no-octal-escape": 2,
|
||||
"no-param-reassign": 0,
|
||||
"no-process-env": 2,
|
||||
"no-proto": 2,
|
||||
"no-redeclare": 2,
|
||||
"no-return-assign": 2,
|
||||
"no-script-url": 2,
|
||||
"no-self-compare": 2,
|
||||
"no-sequences": 2,
|
||||
"no-throw-literal": 2,
|
||||
"no-unused-expressions": 2,
|
||||
"no-void": 0,
|
||||
"no-warning-comments": 1,
|
||||
"no-with": 2,
|
||||
"radix": 2,
|
||||
"vars-on-top": 0,
|
||||
"wrap-iife": 2,
|
||||
"yoda": 0,
|
||||
|
||||
|
||||
// Strict //
|
||||
//--------//
|
||||
"strict": 0,
|
||||
|
||||
|
||||
// Variables //
|
||||
//-----------//
|
||||
"no-catch-shadow": 2,
|
||||
"no-delete-var": 2,
|
||||
"no-label-var": 2,
|
||||
"no-shadow": 2,
|
||||
"no-shadow-restricted-names": 2,
|
||||
"no-undef": 2,
|
||||
"no-undef-init": 2,
|
||||
"no-undefined": 0,
|
||||
"no-unused-vars": [2, {"vars": "all", "args": "after-used"}],
|
||||
"no-use-before-define": [2, "nofunc"],
|
||||
|
||||
|
||||
// Node.js //
|
||||
//---------//
|
||||
// Others left to environment defaults
|
||||
"no-mixed-requires": 0,
|
||||
|
||||
|
||||
// Stylistic //
|
||||
//-----------//
|
||||
"indent": 0,
|
||||
"brace-style": [2, "1tbs", {"allowSingleLine": true}],
|
||||
"camelcase": 2,
|
||||
"comma-spacing": [2, {"before": false, "after": true}],
|
||||
"comma-style": [2, "last"],
|
||||
"consistent-this": [1, "self"],
|
||||
"eol-last": 2,
|
||||
"func-names": 0,
|
||||
"func-style": [2, "declaration"],
|
||||
"key-spacing": [2, {
|
||||
"beforeColon": false,
|
||||
"afterColon": true
|
||||
}],
|
||||
"max-nested-callbacks": 0,
|
||||
"new-cap": 2,
|
||||
"new-parens": 2,
|
||||
"newline-after-var": 0,
|
||||
"no-array-constructor": 2,
|
||||
"no-continue": 0,
|
||||
"no-inline-comments": 0,
|
||||
"no-lonely-if": 2,
|
||||
"no-mixed-spaces-and-tabs": 2,
|
||||
"no-multiple-empty-lines": 0,
|
||||
"no-nested-ternary": 1,
|
||||
"no-new-object": 2,
|
||||
"no-spaced-func": 2,
|
||||
"no-ternary": 0,
|
||||
"no-trailing-spaces": 2,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-wrap-func": 2,
|
||||
"one-var": 0,
|
||||
"operator-assignment": 0,
|
||||
"padded-blocks": 0,
|
||||
"quote-props": 0,
|
||||
"quotes": [2, "single", "avoid-escape"],
|
||||
"semi": 2,
|
||||
"semi-spacing": [2, {"before": false, "after": true}],
|
||||
"sort-vars": 0,
|
||||
"space-after-keywords": [2, "always"],
|
||||
"space-before-blocks": [2, "always"],
|
||||
"space-before-function-paren": [2, {"anonymous": "never", "named": "never"}],
|
||||
"space-in-brackets": 0,
|
||||
"space-in-parens": [2, "never"],
|
||||
"space-infix-ops": 2,
|
||||
"space-return-throw-case": 2,
|
||||
"space-unary-ops": 2,
|
||||
"spaced-line-comment": 2,
|
||||
"wrap-regex": 1
|
||||
}
|
||||
}
|
||||
+62
-37
@@ -1,16 +1,16 @@
|
||||
var childProcess = require('child_process');
|
||||
|
||||
/*eslint-disable no-process-env */
|
||||
module.exports = function(grunt) {
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
|
||||
jshint: {
|
||||
eslint: {
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
},
|
||||
files: [
|
||||
'dist/cjs/**/!(*.min|parser).js'
|
||||
'*.js',
|
||||
'lib/**/!(*.min|parser).js',
|
||||
'spec/**/!(*.amd|json2|require).js'
|
||||
]
|
||||
},
|
||||
|
||||
@@ -19,7 +19,7 @@ module.exports = function(grunt) {
|
||||
copy: {
|
||||
dist: {
|
||||
options: {
|
||||
processContent: function(content, path) {
|
||||
processContent: function(content) {
|
||||
return grunt.template.process('/*!\n\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n@license\n*/\n')
|
||||
+ content;
|
||||
}
|
||||
@@ -41,54 +41,78 @@ module.exports = function(grunt) {
|
||||
}
|
||||
},
|
||||
|
||||
packager: {
|
||||
global: {
|
||||
type: 'umd',
|
||||
export: 'Handlebars',
|
||||
files: [{
|
||||
cwd: 'lib/',
|
||||
expand: true,
|
||||
src: ['handlebars*.js'],
|
||||
dest: 'dist/'
|
||||
}]
|
||||
babel: {
|
||||
options: {
|
||||
loose: ['es6.modules']
|
||||
},
|
||||
|
||||
amd: {
|
||||
type: 'amd',
|
||||
anonymous: true,
|
||||
options: {
|
||||
modules: 'amd'
|
||||
},
|
||||
files: [{
|
||||
expand: true,
|
||||
cwd: 'lib/',
|
||||
src: '**/!(index).js',
|
||||
src: '**/!(index|precompiler).js',
|
||||
dest: 'dist/amd/'
|
||||
}]
|
||||
},
|
||||
|
||||
cjs: {
|
||||
type: 'cjs',
|
||||
options: {
|
||||
modules: 'common'
|
||||
},
|
||||
files: [{
|
||||
expand: true,
|
||||
cwd: 'lib/',
|
||||
expand: true,
|
||||
src: '**/!(index).js',
|
||||
dest: 'dist/cjs/'
|
||||
}]
|
||||
}
|
||||
},
|
||||
webpack: {
|
||||
options: {
|
||||
context: __dirname,
|
||||
module: {
|
||||
loaders: [
|
||||
// the optional 'runtime' transformer tells babel to require the runtime instead of inlining it.
|
||||
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?optional=runtime&loose=es6.modules' }
|
||||
]
|
||||
},
|
||||
output: {
|
||||
path: 'dist/',
|
||||
library: 'Handlebars',
|
||||
libraryTarget: 'umd'
|
||||
}
|
||||
},
|
||||
handlebars: {
|
||||
entry: './lib/handlebars.js',
|
||||
output: {
|
||||
filename: 'handlebars.js'
|
||||
}
|
||||
},
|
||||
runtime: {
|
||||
entry: './lib/handlebars.runtime.js',
|
||||
output: {
|
||||
filename: 'handlebars.runtime.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
requirejs: {
|
||||
options: {
|
||||
optimize: "none",
|
||||
baseUrl: "dist/amd/"
|
||||
optimize: 'none',
|
||||
baseUrl: 'dist/amd/'
|
||||
},
|
||||
dist: {
|
||||
options: {
|
||||
name: "handlebars",
|
||||
out: "dist/handlebars.amd.js"
|
||||
name: 'handlebars',
|
||||
out: 'dist/handlebars.amd.js'
|
||||
}
|
||||
},
|
||||
runtime: {
|
||||
options: {
|
||||
name: "handlebars.runtime",
|
||||
out: "dist/handlebars.runtime.amd.js"
|
||||
name: 'handlebars.runtime',
|
||||
out: 'dist/handlebars.runtime.amd.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -172,18 +196,18 @@ module.exports = function(grunt) {
|
||||
});
|
||||
|
||||
// Build a new version of the library
|
||||
this.registerTask('build', "Builds a distributable version of the current project", [
|
||||
this.registerTask('build', 'Builds a distributable version of the current project', [
|
||||
'eslint',
|
||||
'parser',
|
||||
'node',
|
||||
'globals',
|
||||
'jshint']);
|
||||
'globals']);
|
||||
|
||||
this.registerTask('amd', ['packager:amd', 'requirejs']);
|
||||
this.registerTask('node', ['packager:cjs']);
|
||||
this.registerTask('globals', ['packager:global']);
|
||||
this.registerTask('amd', ['babel:amd', 'requirejs']);
|
||||
this.registerTask('node', ['babel:cjs']);
|
||||
this.registerTask('globals', ['webpack']);
|
||||
this.registerTask('tests', ['concat:tests']);
|
||||
|
||||
this.registerTask('release', 'Build final packages', ['amd', 'jshint', 'uglify', 'copy:dist', 'copy:components', 'copy:cdnjs']);
|
||||
this.registerTask('release', 'Build final packages', ['eslint', 'amd', 'uglify', 'copy:dist', 'copy:components', 'copy:cdnjs']);
|
||||
|
||||
// Load tasks from npm
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
@@ -191,11 +215,12 @@ module.exports = function(grunt) {
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-requirejs');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-babel');
|
||||
grunt.loadNpmTasks('grunt-eslint');
|
||||
grunt.loadNpmTasks('grunt-saucelabs');
|
||||
grunt.loadNpmTasks('es6-module-packager');
|
||||
grunt.loadNpmTasks('grunt-webpack');
|
||||
|
||||
grunt.task.loadTasks('tasks');
|
||||
|
||||
|
||||
+18
-20
@@ -1,21 +1,20 @@
|
||||
/*globals Handlebars: true */
|
||||
import Handlebars from "./handlebars.runtime";
|
||||
import Handlebars from './handlebars.runtime';
|
||||
|
||||
// Compiler imports
|
||||
import 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";
|
||||
import Visitor from "./handlebars/compiler/visitor";
|
||||
import 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';
|
||||
import Visitor from './handlebars/compiler/visitor';
|
||||
|
||||
var _create = Handlebars.create;
|
||||
var create = function() {
|
||||
function create() {
|
||||
var hb = _create();
|
||||
|
||||
hb.compile = function(input, options) {
|
||||
return compile(input, options, hb);
|
||||
};
|
||||
hb.precompile = function (input, options) {
|
||||
hb.precompile = function(input, options) {
|
||||
return precompile(input, options, hb);
|
||||
};
|
||||
|
||||
@@ -26,24 +25,23 @@ var create = function() {
|
||||
hb.parse = parse;
|
||||
|
||||
return hb;
|
||||
};
|
||||
}
|
||||
|
||||
Handlebars = create();
|
||||
Handlebars.create = create;
|
||||
var inst = create();
|
||||
inst.create = create;
|
||||
|
||||
Handlebars.Visitor = Visitor;
|
||||
inst.Visitor = Visitor;
|
||||
|
||||
/*jshint -W040 */
|
||||
/* istanbul ignore next */
|
||||
var root = typeof global !== 'undefined' ? global : window,
|
||||
$Handlebars = root.Handlebars;
|
||||
var $Handlebars = global.Handlebars;
|
||||
/* istanbul ignore next */
|
||||
Handlebars.noConflict = function() {
|
||||
if (root.Handlebars === Handlebars) {
|
||||
root.Handlebars = $Handlebars;
|
||||
inst.noConflict = function() {
|
||||
if (global.Handlebars === inst) {
|
||||
global.Handlebars = $Handlebars;
|
||||
}
|
||||
};
|
||||
|
||||
Handlebars['default'] = Handlebars;
|
||||
inst['default'] = inst;
|
||||
|
||||
export default Handlebars;
|
||||
export default inst;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/*globals Handlebars: true */
|
||||
module base from "./handlebars/base";
|
||||
/*global window */
|
||||
import * as 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";
|
||||
import SafeString from './handlebars/safe-string';
|
||||
import Exception from './handlebars/exception';
|
||||
import * as Utils from './handlebars/utils';
|
||||
import * as runtime from './handlebars/runtime';
|
||||
|
||||
// For compatibility and usage outside of module systems, make the Handlebars object a namespace
|
||||
var create = function() {
|
||||
function create() {
|
||||
var hb = new base.HandlebarsEnvironment();
|
||||
|
||||
Utils.extend(hb, base);
|
||||
@@ -24,7 +24,7 @@ var create = function() {
|
||||
};
|
||||
|
||||
return hb;
|
||||
};
|
||||
}
|
||||
|
||||
var Handlebars = create();
|
||||
Handlebars.create = create;
|
||||
|
||||
+31
-31
@@ -1,7 +1,7 @@
|
||||
module Utils from "./utils";
|
||||
import Exception from "./exception";
|
||||
import * as Utils from './utils';
|
||||
import Exception from './exception';
|
||||
|
||||
export var VERSION = "3.0.1";
|
||||
export var VERSION = '3.0.1';
|
||||
export var COMPILER_REVISION = 6;
|
||||
|
||||
export var REVISION_CHANGES = {
|
||||
@@ -45,7 +45,7 @@ HandlebarsEnvironment.prototype = {
|
||||
|
||||
registerPartial: function(name, partial) {
|
||||
if (toString.call(name) === objectType) {
|
||||
Utils.extend(this.partials, name);
|
||||
Utils.extend(this.partials, name);
|
||||
} else {
|
||||
if (typeof partial === 'undefined') {
|
||||
throw new Exception('Attempting to register a partial as undefined');
|
||||
@@ -60,12 +60,12 @@ HandlebarsEnvironment.prototype = {
|
||||
|
||||
function registerDefaultHelpers(instance) {
|
||||
instance.registerHelper('helperMissing', function(/* [args, ]options */) {
|
||||
if(arguments.length === 1) {
|
||||
if (arguments.length === 1) {
|
||||
// A missing field in a {{foo}} constuct.
|
||||
return undefined;
|
||||
} else {
|
||||
// Someone is actually trying to call something, blow up.
|
||||
throw new Exception("Missing helper: '" + arguments[arguments.length-1].name + "'");
|
||||
throw new Exception('Missing helper: "' + arguments[arguments.length - 1].name + '"');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -73,12 +73,12 @@ function registerDefaultHelpers(instance) {
|
||||
var inverse = options.inverse,
|
||||
fn = options.fn;
|
||||
|
||||
if(context === true) {
|
||||
if (context === true) {
|
||||
return fn(this);
|
||||
} else if(context === false || context == null) {
|
||||
} else if (context === false || context == null) {
|
||||
return inverse(this);
|
||||
} else if (isArray(context)) {
|
||||
if(context.length > 0) {
|
||||
if (context.length > 0) {
|
||||
if (options.ids) {
|
||||
options.ids = [options.name];
|
||||
}
|
||||
@@ -104,7 +104,7 @@ function registerDefaultHelpers(instance) {
|
||||
}
|
||||
|
||||
var fn = options.fn, inverse = options.inverse;
|
||||
var i = 0, ret = "", data;
|
||||
var i = 0, ret = '', data;
|
||||
|
||||
var contextPath;
|
||||
if (options.data && options.ids) {
|
||||
@@ -117,51 +117,51 @@ function registerDefaultHelpers(instance) {
|
||||
data = createFrame(options.data);
|
||||
}
|
||||
|
||||
function execIteration(key, i, last) {
|
||||
function execIteration(field, index, last) {
|
||||
if (data) {
|
||||
data.key = key;
|
||||
data.index = i;
|
||||
data.first = i === 0;
|
||||
data.last = !!last;
|
||||
data.key = field;
|
||||
data.index = index;
|
||||
data.first = index === 0;
|
||||
data.last = !!last;
|
||||
|
||||
if (contextPath) {
|
||||
data.contextPath = contextPath + key;
|
||||
data.contextPath = contextPath + field;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ret + fn(context[key], {
|
||||
ret = ret + fn(context[field], {
|
||||
data: data,
|
||||
blockParams: Utils.blockParams([context[key], key], [contextPath + key, null])
|
||||
blockParams: Utils.blockParams([context[field], field], [contextPath + field, null])
|
||||
});
|
||||
}
|
||||
|
||||
if(context && typeof context === 'object') {
|
||||
if (context && typeof context === 'object') {
|
||||
if (isArray(context)) {
|
||||
for(var j = context.length; i<j; i++) {
|
||||
execIteration(i, i, i === context.length-1);
|
||||
for (var j = context.length; i < j; i++) {
|
||||
execIteration(i, i, i === context.length - 1);
|
||||
}
|
||||
} else {
|
||||
var priorKey;
|
||||
|
||||
for(var key in context) {
|
||||
if(context.hasOwnProperty(key)) {
|
||||
for (var key in context) {
|
||||
if (context.hasOwnProperty(key)) {
|
||||
// We're running the iterations one step out of sync so we can detect
|
||||
// the last iteration without have to scan the object twice and create
|
||||
// an itermediate keys array.
|
||||
// an itermediate keys array.
|
||||
if (priorKey) {
|
||||
execIteration(priorKey, i-1);
|
||||
execIteration(priorKey, i - 1);
|
||||
}
|
||||
priorKey = key;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (priorKey) {
|
||||
execIteration(priorKey, i-1, true);
|
||||
execIteration(priorKey, i - 1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(i === 0){
|
||||
if (i === 0) {
|
||||
ret = inverse(this);
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ function registerDefaultHelpers(instance) {
|
||||
if (options.data && options.ids) {
|
||||
var data = createFrame(options.data);
|
||||
data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]);
|
||||
options = {data:data};
|
||||
options = {data: data};
|
||||
}
|
||||
|
||||
return fn(context, options);
|
||||
@@ -227,15 +227,15 @@ export var logger = {
|
||||
log: function(level, message) {
|
||||
if (typeof console !== 'undefined' && logger.level <= level) {
|
||||
var method = logger.methodMap[level];
|
||||
(console[method] || console.log).call(console, message);
|
||||
(console[method] || console.log).call(console, message); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export var log = logger.log;
|
||||
|
||||
export var createFrame = function(object) {
|
||||
export function createFrame(object) {
|
||||
var frame = Utils.extend({}, object);
|
||||
frame._parent = object;
|
||||
return frame;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ var AST = {
|
||||
this.path = path;
|
||||
this.params = params || [];
|
||||
this.hash = hash;
|
||||
this.program = program;
|
||||
this.inverse = inverse;
|
||||
this.program = program;
|
||||
this.inverse = inverse;
|
||||
|
||||
this.openStrip = openStrip;
|
||||
this.inverseStrip = inverseStrip;
|
||||
@@ -76,8 +76,8 @@ var AST = {
|
||||
|
||||
this.data = data;
|
||||
this.original = original;
|
||||
this.parts = parts;
|
||||
this.depth = depth;
|
||||
this.parts = parts;
|
||||
this.depth = depth;
|
||||
},
|
||||
|
||||
StringLiteral: function(string, locInfo) {
|
||||
@@ -130,7 +130,6 @@ var AST = {
|
||||
// a mustache is definitely a helper if:
|
||||
// * it is an eligible helper, and
|
||||
// * it has at least one parameter or hash segment
|
||||
// TODO: Make these public utility methods
|
||||
helperExpression: function(node) {
|
||||
return !!(node.type === 'SubExpression' || node.params.length || node.hash);
|
||||
},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import parser from "./parser";
|
||||
import AST from "./ast";
|
||||
import WhitespaceControl from "./whitespace-control";
|
||||
module Helpers from "./helpers";
|
||||
import { extend } from "../utils";
|
||||
import parser from './parser';
|
||||
import AST from './ast';
|
||||
import WhitespaceControl from './whitespace-control';
|
||||
import * as Helpers from './helpers';
|
||||
import { extend } from '../utils';
|
||||
|
||||
export { parser };
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {isArray} from "../utils";
|
||||
/*global define */
|
||||
import {isArray} from '../utils';
|
||||
|
||||
var SourceNode;
|
||||
|
||||
@@ -56,7 +57,7 @@ function castChunk(chunk, codeGen, loc) {
|
||||
return ret;
|
||||
} else if (typeof chunk === 'boolean' || typeof chunk === 'number') {
|
||||
// Handle primitives that the SourceNode will throw up on
|
||||
return chunk+'';
|
||||
return chunk + '';
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
@@ -90,7 +91,7 @@ CodeGen.prototype = {
|
||||
},
|
||||
|
||||
empty: function(loc) {
|
||||
loc = loc || this.currentLocation || {start:{}};
|
||||
loc = loc || this.currentLocation || {start: {}};
|
||||
return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
|
||||
},
|
||||
wrap: function(chunk, loc) {
|
||||
@@ -98,7 +99,7 @@ CodeGen.prototype = {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
loc = loc || this.currentLocation || {start:{}};
|
||||
loc = loc || this.currentLocation || {start: {}};
|
||||
chunk = castChunk(chunk, this, loc);
|
||||
|
||||
return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Exception from "../exception";
|
||||
import {isArray, indexOf} from "../utils";
|
||||
import AST from "./ast";
|
||||
import Exception from '../exception';
|
||||
import {isArray, indexOf} from '../utils';
|
||||
import AST from './ast';
|
||||
|
||||
var slice = [].slice;
|
||||
|
||||
@@ -67,7 +67,9 @@ Compiler.prototype = {
|
||||
};
|
||||
if (knownHelpers) {
|
||||
for (var name in knownHelpers) {
|
||||
options.knownHelpers[name] = knownHelpers[name];
|
||||
if (name in knownHelpers) {
|
||||
options.knownHelpers[name] = knownHelpers[name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +77,7 @@ Compiler.prototype = {
|
||||
},
|
||||
|
||||
compileProgram: function(program) {
|
||||
var result = new this.compiler().compile(program, this.options);
|
||||
var result = new this.compiler().compile(program, this.options); // eslint-disable-line new-cap
|
||||
var guid = this.guid++;
|
||||
|
||||
this.usePartial = this.usePartial || result.usePartial;
|
||||
@@ -97,7 +99,7 @@ Compiler.prototype = {
|
||||
this.options.blockParams.unshift(program.blockParams);
|
||||
|
||||
var body = program.body;
|
||||
for(var i=0, l=body.length; i<l; i++) {
|
||||
for (var i = 0, l = body.length; i < l; i++) {
|
||||
this.accept(body[i]);
|
||||
}
|
||||
|
||||
@@ -174,9 +176,9 @@ Compiler.prototype = {
|
||||
},
|
||||
|
||||
MustacheStatement: function(mustache) {
|
||||
this.SubExpression(mustache);
|
||||
this.SubExpression(mustache); // eslint-disable-line new-cap
|
||||
|
||||
if(mustache.escaped && !this.options.noEscape) {
|
||||
if (mustache.escaped && !this.options.noEscape) {
|
||||
this.opcode('appendEscaped');
|
||||
} else {
|
||||
this.opcode('append');
|
||||
@@ -231,7 +233,7 @@ Compiler.prototype = {
|
||||
if (this.options.knownHelpers[name]) {
|
||||
this.opcode('invokeKnownHelper', params.length, name);
|
||||
} else if (this.options.knownHelpersOnly) {
|
||||
throw new Exception("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr);
|
||||
throw new Exception('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr);
|
||||
} else {
|
||||
path.falsy = true;
|
||||
|
||||
@@ -250,7 +252,7 @@ Compiler.prototype = {
|
||||
|
||||
if (blockParamId) {
|
||||
this.opcode('lookupBlockParam', blockParamId, path.parts);
|
||||
} else if (!name) {
|
||||
} else if (!name) {
|
||||
// Context reference, i.e. `{{foo .}}` or `{{foo ..}}`
|
||||
this.opcode('pushContext');
|
||||
} else if (path.data) {
|
||||
@@ -286,7 +288,7 @@ Compiler.prototype = {
|
||||
|
||||
this.opcode('pushHash');
|
||||
|
||||
for (i=0, l=pairs.length; i<l; i++) {
|
||||
for (i = 0, l = pairs.length; i < l; i++) {
|
||||
this.pushParam(pairs[i].value);
|
||||
}
|
||||
while (i--) {
|
||||
@@ -336,13 +338,17 @@ Compiler.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
if (isHelper) { return 'helper'; }
|
||||
else if (isEligible) { return 'ambiguous'; }
|
||||
else { return 'simple'; }
|
||||
if (isHelper) {
|
||||
return 'helper';
|
||||
} else if (isEligible) {
|
||||
return 'ambiguous';
|
||||
} else {
|
||||
return 'simple';
|
||||
}
|
||||
},
|
||||
|
||||
pushParams: function(params) {
|
||||
for(var i=0, l=params.length; i<l; i++) {
|
||||
for (var i = 0, l = params.length; i < l; i++) {
|
||||
this.pushParam(params[i]);
|
||||
}
|
||||
},
|
||||
@@ -357,7 +363,7 @@ Compiler.prototype = {
|
||||
.replace(/\//g, '.');
|
||||
}
|
||||
|
||||
if(val.depth) {
|
||||
if (val.depth) {
|
||||
this.addDepth(val.depth);
|
||||
}
|
||||
this.opcode('getContext', val.depth || 0);
|
||||
@@ -421,7 +427,7 @@ Compiler.prototype = {
|
||||
|
||||
export function precompile(input, options, env) {
|
||||
if (input == null || (typeof input !== 'string' && input.type !== 'Program')) {
|
||||
throw new Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input);
|
||||
throw new Exception('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input);
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
@@ -439,7 +445,7 @@ export function precompile(input, options, env) {
|
||||
|
||||
export function compile(input, options, env) {
|
||||
if (input == null || (typeof input !== 'string' && input.type !== 'Program')) {
|
||||
throw new Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
|
||||
throw new Exception('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input);
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
@@ -461,17 +467,17 @@ export function compile(input, options, env) {
|
||||
}
|
||||
|
||||
// Template is only compiled on first use and cached after that point.
|
||||
var ret = function(context, options) {
|
||||
function ret(context, execOptions) {
|
||||
if (!compiled) {
|
||||
compiled = compileInput();
|
||||
}
|
||||
return compiled.call(this, context, options);
|
||||
};
|
||||
ret._setup = function(options) {
|
||||
return compiled.call(this, context, execOptions);
|
||||
}
|
||||
ret._setup = function(setupOptions) {
|
||||
if (!compiled) {
|
||||
compiled = compileInput();
|
||||
}
|
||||
return compiled._setup(options);
|
||||
return compiled._setup(setupOptions);
|
||||
};
|
||||
ret._child = function(i, data, blockParams, depths) {
|
||||
if (!compiled) {
|
||||
@@ -502,6 +508,6 @@ function transformLiteralToPath(sexpr) {
|
||||
var literal = sexpr.path;
|
||||
// Casting to string here to make false and 0 literal values play nicely with the rest
|
||||
// of the system.
|
||||
sexpr.path = new AST.PathExpression(false, 0, [literal.original+''], literal.original+'', literal.loc);
|
||||
sexpr.path = new AST.PathExpression(false, 0, [literal.original + ''], literal.original + '', literal.loc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Exception from "../exception";
|
||||
import Exception from '../exception';
|
||||
|
||||
export function SourceLocation(source, locInfo) {
|
||||
this.source = source;
|
||||
@@ -23,7 +23,7 @@ export function id(token) {
|
||||
export function stripFlags(open, close) {
|
||||
return {
|
||||
open: open.charAt(2) === '~',
|
||||
close: close.charAt(close.length-3) === '~'
|
||||
close: close.charAt(close.length - 3) === '~'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export function preparePath(data, parts, locInfo) {
|
||||
depth = 0,
|
||||
depthString = '';
|
||||
|
||||
for(var i=0,l=parts.length; i<l; i++) {
|
||||
for (var i = 0, l = parts.length; i < l; i++) {
|
||||
var part = parts[i].part,
|
||||
// If we have [] syntax then we do not treat path references as operators,
|
||||
// i.e. foo.[this] resolves to approximately context.foo['this']
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { COMPILER_REVISION, REVISION_CHANGES } from "../base";
|
||||
import Exception from "../exception";
|
||||
import {isArray} from "../utils";
|
||||
import CodeGen from "./code-gen";
|
||||
import { COMPILER_REVISION, REVISION_CHANGES } from '../base';
|
||||
import Exception from '../exception';
|
||||
import {isArray} from '../utils';
|
||||
import CodeGen from './code-gen';
|
||||
|
||||
function Literal(value) {
|
||||
this.value = value;
|
||||
@@ -14,7 +14,7 @@ JavaScriptCompiler.prototype = {
|
||||
// alternative compiled forms for name lookup and buffering semantics
|
||||
nameLookup: function(parent, name /* , type*/) {
|
||||
if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
|
||||
return [parent, ".", name];
|
||||
return [parent, '.', name];
|
||||
} else {
|
||||
return [parent, "['", name, "']"];
|
||||
}
|
||||
@@ -50,7 +50,7 @@ JavaScriptCompiler.prototype = {
|
||||
},
|
||||
|
||||
initializeBuffer: function() {
|
||||
return this.quotedString("");
|
||||
return this.quotedString('');
|
||||
},
|
||||
// END PUBLIC API
|
||||
|
||||
@@ -169,8 +169,8 @@ JavaScriptCompiler.prototype = {
|
||||
var varDeclarations = '';
|
||||
|
||||
var locals = this.stackVars.concat(this.registers.list);
|
||||
if(locals.length > 0) {
|
||||
varDeclarations += ", " + locals.join(", ");
|
||||
if (locals.length > 0) {
|
||||
varDeclarations += ', ' + locals.join(', ');
|
||||
}
|
||||
|
||||
// Generate minimizer alias mappings
|
||||
@@ -180,7 +180,7 @@ JavaScriptCompiler.prototype = {
|
||||
// aliases will not be used, but this case is already being run on the client and
|
||||
// we aren't concern about minimizing the template size.
|
||||
var aliasCount = 0;
|
||||
for (var alias in this.aliases) {
|
||||
for (var alias in this.aliases) { // eslint-disable-line guard-for-in
|
||||
var node = this.aliases[alias];
|
||||
|
||||
if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) {
|
||||
@@ -189,7 +189,7 @@ JavaScriptCompiler.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
var params = ["depth0", "helpers", "partials", "data"];
|
||||
var params = ['depth0', 'helpers', 'partials', 'data'];
|
||||
|
||||
if (this.useBlockParams || this.useDepths) {
|
||||
params.push('blockParams');
|
||||
@@ -252,7 +252,7 @@ JavaScriptCompiler.prototype = {
|
||||
this.source.push('return "";');
|
||||
}
|
||||
} else {
|
||||
varDeclarations += ", buffer = " + (appendFirst ? '' : this.initializeBuffer());
|
||||
varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer());
|
||||
|
||||
if (bufferStart) {
|
||||
bufferStart.prepend('return buffer + ');
|
||||
@@ -446,6 +446,7 @@ JavaScriptCompiler.prototype = {
|
||||
|
||||
var len = parts.length;
|
||||
for (; i < len; i++) {
|
||||
/*eslint-disable no-loop-func */
|
||||
this.replaceStack(function(current) {
|
||||
var lookup = this.nameLookup(current, parts[i], type);
|
||||
// We want to ensure that zero and false are handled properly if the context (falsy flag)
|
||||
@@ -457,6 +458,7 @@ JavaScriptCompiler.prototype = {
|
||||
return [' && ', lookup];
|
||||
}
|
||||
});
|
||||
/*eslint-enable no-loop-func */
|
||||
}
|
||||
},
|
||||
|
||||
@@ -633,7 +635,7 @@ JavaScriptCompiler.prototype = {
|
||||
'(', lookup,
|
||||
(helper.paramsInit ? ['),(', helper.paramsInit] : []), '),',
|
||||
'(typeof helper === ', this.aliasable('"function"'), ' ? ',
|
||||
this.source.functionCall('helper','call', helper.callParams), ' : helper))'
|
||||
this.source.functionCall('helper', 'call', helper.callParams), ' : helper))'
|
||||
]);
|
||||
},
|
||||
|
||||
@@ -728,9 +730,9 @@ JavaScriptCompiler.prototype = {
|
||||
compileChildren: function(environment, options) {
|
||||
var children = environment.children, child, compiler;
|
||||
|
||||
for(var i=0, l=children.length; i<l; i++) {
|
||||
for (var i = 0, l = children.length; i < l; i++) {
|
||||
child = children[i];
|
||||
compiler = new this.compiler();
|
||||
compiler = new this.compiler(); // eslint-disable-line new-cap
|
||||
|
||||
var index = this.matchExistingProgram(child);
|
||||
|
||||
@@ -777,7 +779,7 @@ JavaScriptCompiler.prototype = {
|
||||
},
|
||||
|
||||
useRegister: function(name) {
|
||||
if(!this.registers[name]) {
|
||||
if (!this.registers[name]) {
|
||||
this.registers[name] = true;
|
||||
this.registers.list.push(name);
|
||||
}
|
||||
@@ -849,11 +851,11 @@ JavaScriptCompiler.prototype = {
|
||||
|
||||
incrStack: function() {
|
||||
this.stackSlot++;
|
||||
if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
|
||||
if (this.stackSlot > this.stackVars.length) { this.stackVars.push('stack' + this.stackSlot); }
|
||||
return this.topStackName();
|
||||
},
|
||||
topStackName: function() {
|
||||
return "stack" + this.stackSlot;
|
||||
return 'stack' + this.stackSlot;
|
||||
},
|
||||
flushInline: function() {
|
||||
var inlineStack = this.inlineStack;
|
||||
@@ -1019,33 +1021,35 @@ JavaScriptCompiler.prototype = {
|
||||
};
|
||||
|
||||
|
||||
var reservedWords = (
|
||||
"break else new var" +
|
||||
" case finally return void" +
|
||||
" catch for switch while" +
|
||||
" continue function this with" +
|
||||
" default if throw" +
|
||||
" delete in try" +
|
||||
" do instanceof typeof" +
|
||||
" abstract enum int short" +
|
||||
" boolean export interface static" +
|
||||
" byte extends long super" +
|
||||
" char final native synchronized" +
|
||||
" class float package throws" +
|
||||
" const goto private transient" +
|
||||
" debugger implements protected volatile" +
|
||||
" double import public let yield await" +
|
||||
" null true false"
|
||||
).split(" ");
|
||||
(function() {
|
||||
var reservedWords = (
|
||||
'break else new var' +
|
||||
' case finally return void' +
|
||||
' catch for switch while' +
|
||||
' continue function this with' +
|
||||
' default if throw' +
|
||||
' delete in try' +
|
||||
' do instanceof typeof' +
|
||||
' abstract enum int short' +
|
||||
' boolean export interface static' +
|
||||
' byte extends long super' +
|
||||
' char final native synchronized' +
|
||||
' class float package throws' +
|
||||
' const goto private transient' +
|
||||
' debugger implements protected volatile' +
|
||||
' double import public let yield await' +
|
||||
' null true false'
|
||||
).split(' ');
|
||||
|
||||
var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
|
||||
var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
|
||||
|
||||
for(var i=0, l=reservedWords.length; i<l; i++) {
|
||||
compilerWords[reservedWords[i]] = true;
|
||||
}
|
||||
for (var i = 0, l = reservedWords.length; i < l; i++) {
|
||||
compilerWords[reservedWords[i]] = true;
|
||||
}
|
||||
}());
|
||||
|
||||
JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
|
||||
return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name);
|
||||
return !JavaScriptCompiler.RESERVED_WORDS[name] && (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/).test(name);
|
||||
};
|
||||
|
||||
function strictLookup(requireTerminal, compiler, parts, type) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Visitor from "./visitor";
|
||||
/*eslint-disable new-cap */
|
||||
import Visitor from './visitor';
|
||||
|
||||
export function print(ast) {
|
||||
return new PrintVisitor().accept(ast);
|
||||
@@ -11,13 +12,13 @@ export function PrintVisitor() {
|
||||
PrintVisitor.prototype = new Visitor();
|
||||
|
||||
PrintVisitor.prototype.pad = function(string) {
|
||||
var out = "";
|
||||
var out = '';
|
||||
|
||||
for(var i=0,l=this.padding; i<l; i++) {
|
||||
out = out + " ";
|
||||
for (var i = 0, l = this.padding; i < l; i++) {
|
||||
out = out + ' ';
|
||||
}
|
||||
|
||||
out = out + string + "\n";
|
||||
out = out + string + '\n';
|
||||
return out;
|
||||
};
|
||||
|
||||
@@ -28,14 +29,14 @@ PrintVisitor.prototype.Program = function(program) {
|
||||
|
||||
if (program.blockParams) {
|
||||
var blockParams = 'BLOCK PARAMS: [';
|
||||
for(i=0, l=program.blockParams.length; i<l; i++) {
|
||||
for (i = 0, l = program.blockParams.length; i < l; i++) {
|
||||
blockParams += ' ' + program.blockParams[i];
|
||||
}
|
||||
blockParams += ' ]';
|
||||
out += this.pad(blockParams);
|
||||
}
|
||||
|
||||
for(i=0, l=body.length; i<l; i++) {
|
||||
for (i = 0, l = body.length; i < l; i++) {
|
||||
out = out + this.accept(body[i]);
|
||||
}
|
||||
|
||||
@@ -49,7 +50,7 @@ PrintVisitor.prototype.MustacheStatement = function(mustache) {
|
||||
};
|
||||
|
||||
PrintVisitor.prototype.BlockStatement = function(block) {
|
||||
var out = "";
|
||||
var out = '';
|
||||
|
||||
out = out + this.pad('BLOCK:');
|
||||
this.padding++;
|
||||
@@ -75,7 +76,7 @@ PrintVisitor.prototype.BlockStatement = function(block) {
|
||||
|
||||
PrintVisitor.prototype.PartialStatement = function(partial) {
|
||||
var content = 'PARTIAL:' + partial.name.original;
|
||||
if(partial.params[0]) {
|
||||
if (partial.params[0]) {
|
||||
content += ' ' + this.accept(partial.params[0]);
|
||||
}
|
||||
if (partial.hash) {
|
||||
@@ -95,15 +96,15 @@ PrintVisitor.prototype.CommentStatement = function(comment) {
|
||||
PrintVisitor.prototype.SubExpression = function(sexpr) {
|
||||
var params = sexpr.params, paramStrings = [], hash;
|
||||
|
||||
for(var i=0, l=params.length; i<l; i++) {
|
||||
for (var i = 0, l = params.length; i < l; i++) {
|
||||
paramStrings.push(this.accept(params[i]));
|
||||
}
|
||||
|
||||
params = "[" + paramStrings.join(", ") + "]";
|
||||
params = '[' + paramStrings.join(', ') + ']';
|
||||
|
||||
hash = sexpr.hash ? " " + this.accept(sexpr.hash) : "";
|
||||
hash = sexpr.hash ? ' ' + this.accept(sexpr.hash) : '';
|
||||
|
||||
return this.accept(sexpr.path) + " " + params + hash;
|
||||
return this.accept(sexpr.path) + ' ' + params + hash;
|
||||
};
|
||||
|
||||
PrintVisitor.prototype.PathExpression = function(id) {
|
||||
@@ -117,11 +118,11 @@ PrintVisitor.prototype.StringLiteral = function(string) {
|
||||
};
|
||||
|
||||
PrintVisitor.prototype.NumberLiteral = function(number) {
|
||||
return "NUMBER{" + number.value + "}";
|
||||
return 'NUMBER{' + number.value + '}';
|
||||
};
|
||||
|
||||
PrintVisitor.prototype.BooleanLiteral = function(bool) {
|
||||
return "BOOLEAN{" + bool.value + "}";
|
||||
return 'BOOLEAN{' + bool.value + '}';
|
||||
};
|
||||
|
||||
PrintVisitor.prototype.UndefinedLiteral = function() {
|
||||
@@ -136,7 +137,7 @@ PrintVisitor.prototype.Hash = function(hash) {
|
||||
var pairs = hash.pairs;
|
||||
var joinedPairs = [];
|
||||
|
||||
for (var i=0, l=pairs.length; i<l; i++) {
|
||||
for (var i = 0, l = pairs.length; i < l; i++) {
|
||||
joinedPairs.push(this.accept(pairs[i]));
|
||||
}
|
||||
|
||||
@@ -145,3 +146,4 @@ PrintVisitor.prototype.Hash = function(hash) {
|
||||
PrintVisitor.prototype.HashPair = function(pair) {
|
||||
return pair.key + '=' + this.accept(pair.value);
|
||||
};
|
||||
/*eslint-enable new-cap */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Exception from "../exception";
|
||||
import AST from "./ast";
|
||||
import Exception from '../exception';
|
||||
import AST from './ast';
|
||||
|
||||
function Visitor() {
|
||||
this.parents = [];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Visitor from "./visitor";
|
||||
import Visitor from './visitor';
|
||||
|
||||
function WhitespaceControl() {
|
||||
}
|
||||
@@ -38,7 +38,7 @@ WhitespaceControl.prototype.Program = function(program) {
|
||||
// If we are on a standalone node, save the indent info for partials
|
||||
if (current.type === 'PartialStatement') {
|
||||
// Pull out the whitespace from the final line
|
||||
current.indent = (/([ \t]+$)/).exec(body[i-1].original)[1];
|
||||
current.indent = (/([ \t]+$)/).exec(body[i - 1].original)[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ WhitespaceControl.prototype.BlockStatement = function(block) {
|
||||
|
||||
// Walk the inverse chain to find the last inverse that is actually in the chain.
|
||||
while (lastInverse.chained) {
|
||||
lastInverse = lastInverse.body[lastInverse.body.length-1].program;
|
||||
lastInverse = lastInverse.body[lastInverse.body.length - 1].program;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,14 +108,11 @@ WhitespaceControl.prototype.BlockStatement = function(block) {
|
||||
// Find standalone else statments
|
||||
if (isPrevWhitespace(program.body)
|
||||
&& isNextWhitespace(firstInverse.body)) {
|
||||
|
||||
omitLeft(program.body);
|
||||
omitRight(firstInverse.body);
|
||||
}
|
||||
} else {
|
||||
if (block.closeStrip.open) {
|
||||
omitLeft(program.body, null, true);
|
||||
}
|
||||
} else if (block.closeStrip.open) {
|
||||
omitLeft(program.body, null, true);
|
||||
}
|
||||
|
||||
return strip;
|
||||
@@ -125,7 +122,7 @@ WhitespaceControl.prototype.MustacheStatement = function(mustache) {
|
||||
return mustache.strip;
|
||||
};
|
||||
|
||||
WhitespaceControl.prototype.PartialStatement =
|
||||
WhitespaceControl.prototype.PartialStatement =
|
||||
WhitespaceControl.prototype.CommentStatement = function(node) {
|
||||
/* istanbul ignore next */
|
||||
var strip = node.strip || {};
|
||||
@@ -144,8 +141,8 @@ function isPrevWhitespace(body, i, isRoot) {
|
||||
|
||||
// Nodes that end with newlines are considered whitespace (but are special
|
||||
// cased for strip operations)
|
||||
var prev = body[i-1],
|
||||
sibling = body[i-2];
|
||||
var prev = body[i - 1],
|
||||
sibling = body[i - 2];
|
||||
if (!prev) {
|
||||
return isRoot;
|
||||
}
|
||||
@@ -159,8 +156,8 @@ function isNextWhitespace(body, i, isRoot) {
|
||||
i = -1;
|
||||
}
|
||||
|
||||
var next = body[i+1],
|
||||
sibling = body[i+2];
|
||||
var next = body[i + 1],
|
||||
sibling = body[i + 2];
|
||||
if (!next) {
|
||||
return isRoot;
|
||||
}
|
||||
|
||||
+30
-30
@@ -1,6 +1,6 @@
|
||||
module Utils from "./utils";
|
||||
import Exception from "./exception";
|
||||
import { COMPILER_REVISION, REVISION_CHANGES, createFrame } from "./base";
|
||||
import * as Utils from './utils';
|
||||
import Exception from './exception';
|
||||
import { COMPILER_REVISION, REVISION_CHANGES, createFrame } from './base';
|
||||
|
||||
export function checkRevision(compilerInfo) {
|
||||
var compilerRevision = compilerInfo && compilerInfo[0] || 1,
|
||||
@@ -10,12 +10,12 @@ export function checkRevision(compilerInfo) {
|
||||
if (compilerRevision < currentRevision) {
|
||||
var runtimeVersions = REVISION_CHANGES[currentRevision],
|
||||
compilerVersions = REVISION_CHANGES[compilerRevision];
|
||||
throw new Exception("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+").");
|
||||
throw new Exception('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 new Exception("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 Exception('Template was precompiled with a newer version of Handlebars than the current runtime. ' +
|
||||
'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ export function checkRevision(compilerInfo) {
|
||||
export function template(templateSpec, env) {
|
||||
/* istanbul ignore next */
|
||||
if (!env) {
|
||||
throw new Exception("No environment passed to template");
|
||||
throw new Exception('No environment passed to template');
|
||||
}
|
||||
if (!templateSpec || !templateSpec.main) {
|
||||
throw new Exception('Unknown template object: ' + typeof templateSpec);
|
||||
@@ -35,7 +35,7 @@ export function template(templateSpec, env) {
|
||||
// for external users to override these as psuedo-supported APIs.
|
||||
env.VM.checkRevision(templateSpec.compiler);
|
||||
|
||||
var invokePartialWrapper = function(partial, context, options) {
|
||||
function invokePartialWrapper(partial, context, options) {
|
||||
if (options.hash) {
|
||||
context = Utils.extend({}, context, options.hash);
|
||||
}
|
||||
@@ -61,9 +61,9 @@ export function template(templateSpec, env) {
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
throw new Exception("The partial " + options.name + " could not be compiled when running in runtime-only mode");
|
||||
throw new Exception('The partial ' + options.name + ' could not be compiled when running in runtime-only mode');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Just add water
|
||||
var container = {
|
||||
@@ -97,34 +97,34 @@ export function template(templateSpec, env) {
|
||||
var programWrapper = this.programs[i],
|
||||
fn = this.fn(i);
|
||||
if (data || depths || blockParams || declaredBlockParams) {
|
||||
programWrapper = program(this, i, fn, data, declaredBlockParams, blockParams, depths);
|
||||
programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths);
|
||||
} else if (!programWrapper) {
|
||||
programWrapper = this.programs[i] = program(this, i, fn);
|
||||
programWrapper = this.programs[i] = wrapProgram(this, i, fn);
|
||||
}
|
||||
return programWrapper;
|
||||
},
|
||||
|
||||
data: function(data, depth) {
|
||||
while (data && depth--) {
|
||||
data = data._parent;
|
||||
data: function(value, depth) {
|
||||
while (value && depth--) {
|
||||
value = value._parent;
|
||||
}
|
||||
return data;
|
||||
return value;
|
||||
},
|
||||
merge: function(param, common) {
|
||||
var ret = param || common;
|
||||
var obj = param || common;
|
||||
|
||||
if (param && common && (param !== common)) {
|
||||
ret = Utils.extend({}, common, param);
|
||||
obj = Utils.extend({}, common, param);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return obj;
|
||||
},
|
||||
|
||||
noop: env.VM.noop,
|
||||
compilerInfo: templateSpec.compiler
|
||||
};
|
||||
|
||||
var ret = function(context, options) {
|
||||
function ret(context, options) {
|
||||
options = options || {};
|
||||
var data = options.data;
|
||||
|
||||
@@ -139,7 +139,7 @@ export function template(templateSpec, env) {
|
||||
}
|
||||
|
||||
return templateSpec.main.call(container, context, container.helpers, container.partials, data, blockParams, depths);
|
||||
};
|
||||
}
|
||||
ret.isTop = true;
|
||||
|
||||
ret._setup = function(options) {
|
||||
@@ -163,13 +163,13 @@ export function template(templateSpec, env) {
|
||||
throw new Exception('must pass parent depths');
|
||||
}
|
||||
|
||||
return program(container, i, templateSpec[i], data, 0, blockParams, depths);
|
||||
return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths);
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function program(container, i, fn, data, declaredBlockParams, blockParams, depths) {
|
||||
var prog = function(context, options) {
|
||||
export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
|
||||
function prog(context, options) {
|
||||
options = options || {};
|
||||
|
||||
return fn.call(container,
|
||||
@@ -178,7 +178,7 @@ export function program(container, i, fn, data, declaredBlockParams, blockParams
|
||||
options.data || data,
|
||||
blockParams && [options.blockParams].concat(blockParams),
|
||||
depths && [context].concat(depths));
|
||||
};
|
||||
}
|
||||
prog.program = i;
|
||||
prog.depth = depths ? depths.length : 0;
|
||||
prog.blockParams = declaredBlockParams || 0;
|
||||
@@ -199,14 +199,14 @@ export function resolvePartial(partial, context, options) {
|
||||
export function invokePartial(partial, context, options) {
|
||||
options.partial = true;
|
||||
|
||||
if(partial === undefined) {
|
||||
throw new Exception("The partial " + options.name + " could not be found");
|
||||
} else if(partial instanceof Function) {
|
||||
if (partial === undefined) {
|
||||
throw new Exception('The partial ' + options.name + ' could not be found');
|
||||
} else if (partial instanceof Function) {
|
||||
return partial(context, options);
|
||||
}
|
||||
}
|
||||
|
||||
export function noop() { return ""; }
|
||||
export function noop() { return ''; }
|
||||
|
||||
function initData(context, data) {
|
||||
if (!data || !('root' in data)) {
|
||||
|
||||
@@ -4,7 +4,7 @@ function SafeString(string) {
|
||||
}
|
||||
|
||||
SafeString.prototype.toString = SafeString.prototype.toHTML = function() {
|
||||
return "" + this.string;
|
||||
return '' + this.string;
|
||||
};
|
||||
|
||||
export default SafeString;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*jshint -W004 */
|
||||
var escape = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': """,
|
||||
"'": "'",
|
||||
"`": "`"
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'`': '`'
|
||||
};
|
||||
|
||||
var badChars = /[&<>"'`]/g;
|
||||
@@ -31,6 +31,7 @@ export var toString = Object.prototype.toString;
|
||||
|
||||
// Sourced from lodash
|
||||
// https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
|
||||
/*eslint-disable func-style */
|
||||
var isFunction = function(value) {
|
||||
return typeof value === 'function';
|
||||
};
|
||||
@@ -42,6 +43,7 @@ if (isFunction(/x/)) {
|
||||
};
|
||||
}
|
||||
export var isFunction;
|
||||
/*eslint-enable func-style */
|
||||
|
||||
/* istanbul ignore next */
|
||||
export var isArray = Array.isArray || function(value) {
|
||||
|
||||
+8
-8
@@ -3,7 +3,7 @@
|
||||
|
||||
// var local = handlebars.create();
|
||||
|
||||
var handlebars = require('../dist/cjs/handlebars')["default"];
|
||||
var handlebars = require('../dist/cjs/handlebars')['default'];
|
||||
|
||||
var printer = require('../dist/cjs/handlebars/compiler/printer');
|
||||
handlebars.PrintVisitor = printer.PrintVisitor;
|
||||
@@ -12,13 +12,13 @@ handlebars.print = printer.print;
|
||||
module.exports = handlebars;
|
||||
|
||||
// Publish a Node.js require() handler for .handlebars and .hbs files
|
||||
function extension(module, filename) {
|
||||
var fs = require('fs');
|
||||
var templateString = fs.readFileSync(filename, 'utf8');
|
||||
module.exports = handlebars.compile(templateString);
|
||||
}
|
||||
/* istanbul ignore else */
|
||||
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;
|
||||
require.extensions['.handlebars'] = extension;
|
||||
require.extensions['.hbs'] = extension;
|
||||
}
|
||||
|
||||
+9
-9
@@ -1,4 +1,4 @@
|
||||
|
||||
/*eslint-disable no-console */
|
||||
var fs = require('fs'),
|
||||
Handlebars = require('./index'),
|
||||
basename = require('path').basename,
|
||||
@@ -70,10 +70,10 @@ module.exports.cli = function(opts) {
|
||||
stat = fs.statSync(path);
|
||||
if (stat.isDirectory()) {
|
||||
fs.readdirSync(template).map(function(file) {
|
||||
var path = template + '/' + file;
|
||||
var childPath = template + '/' + file;
|
||||
|
||||
if (extension.test(path) || fs.statSync(path).isDirectory()) {
|
||||
processTemplate(path, root || template);
|
||||
if (extension.test(childPath) || fs.statSync(childPath).isDirectory()) {
|
||||
processTemplate(childPath, root || template);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -99,7 +99,7 @@ module.exports.cli = function(opts) {
|
||||
if (!root) {
|
||||
template = basename(template);
|
||||
} else if (template.indexOf(root) === 0) {
|
||||
template = template.substring(root.length+1);
|
||||
template = template.substring(root.length + 1);
|
||||
}
|
||||
template = template.replace(extension, '');
|
||||
|
||||
@@ -114,12 +114,12 @@ module.exports.cli = function(opts) {
|
||||
if (opts.simple) {
|
||||
output.add([precompiled, '\n']);
|
||||
} else if (opts.partial) {
|
||||
if(opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
|
||||
if (opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
|
||||
output.add('return ');
|
||||
}
|
||||
output.add(['Handlebars.partials[\'', template, '\'] = template(', precompiled, ');\n']);
|
||||
} else {
|
||||
if(opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
|
||||
if (opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
|
||||
output.add('return ');
|
||||
}
|
||||
output.add(['templates[\'', template, '\'] = template(', precompiled, ');\n']);
|
||||
@@ -134,8 +134,8 @@ module.exports.cli = function(opts) {
|
||||
// Output the content
|
||||
if (!opts.simple) {
|
||||
if (opts.amd) {
|
||||
if(opts.templates.length > 1 || (opts.templates.length == 1 && fs.statSync(opts.templates[0]).isDirectory())) {
|
||||
if(opts.partial){
|
||||
if (opts.templates.length > 1 || (opts.templates.length == 1 && fs.statSync(opts.templates[0]).isDirectory())) {
|
||||
if (opts.partial) {
|
||||
output.add('return Handlebars.partials;\n');
|
||||
} else {
|
||||
output.add('return templates;\n');
|
||||
|
||||
+5
-1
@@ -30,11 +30,13 @@
|
||||
"devDependencies": {
|
||||
"async": "^0.9.0",
|
||||
"aws-sdk": "~1.5.0",
|
||||
"babel-loader": "^5.0.0",
|
||||
"babel-runtime": "^5.1.10",
|
||||
"benchmark": "~1.0",
|
||||
"dustjs-linkedin": "^2.0.2",
|
||||
"eco": "~1.1.0-rc-3",
|
||||
"es6-module-packager": "^2.0.0",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-babel": "^5.0.0",
|
||||
"grunt-cli": "~0.1.10",
|
||||
"grunt-contrib-clean": "0.x",
|
||||
"grunt-contrib-concat": "0.x",
|
||||
@@ -44,7 +46,9 @@
|
||||
"grunt-contrib-requirejs": "0.x",
|
||||
"grunt-contrib-uglify": "0.x",
|
||||
"grunt-contrib-watch": "0.x",
|
||||
"grunt-eslint": "^11.0.0",
|
||||
"grunt-saucelabs": "8.x",
|
||||
"grunt-webpack": "^1.0.8",
|
||||
"istanbul": "^0.3.0",
|
||||
"jison": "~0.3.0",
|
||||
"keen.io": "0.0.3",
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"globals": {
|
||||
"CompilerContext": true,
|
||||
"Handlebars": true,
|
||||
"handlebarsEnv": true,
|
||||
|
||||
"shouldCompileTo": true,
|
||||
"shouldCompileToWithPartials": true,
|
||||
"shouldThrow": true,
|
||||
"compileWithPartials": true,
|
||||
|
||||
"console": true,
|
||||
"require": true,
|
||||
"suite": true,
|
||||
"equal": true,
|
||||
"equals": true,
|
||||
"test": true,
|
||||
"testBoth": true,
|
||||
"raises": true,
|
||||
"deepEqual": true,
|
||||
"start": true,
|
||||
"stop": true,
|
||||
"ok": true,
|
||||
"strictEqual": true,
|
||||
"define": true
|
||||
},
|
||||
"env": {
|
||||
"mocha": true
|
||||
},
|
||||
"rules": {
|
||||
// Disabling for tests, for now.
|
||||
"no-path-concat": 0
|
||||
}
|
||||
}
|
||||
+38
-41
@@ -1,4 +1,3 @@
|
||||
/*global Handlebars, handlebarsEnv, shouldThrow */
|
||||
describe('ast', function() {
|
||||
if (!Handlebars.AST) {
|
||||
return;
|
||||
@@ -15,7 +14,7 @@ describe('ast', function() {
|
||||
}
|
||||
};
|
||||
|
||||
function testLocationInfoStorage(node){
|
||||
function testLocationInfoStorage(node) {
|
||||
equals(node.loc.start.line, 1);
|
||||
equals(node.loc.start.column, 1);
|
||||
equals(node.loc.end.line, 1);
|
||||
@@ -24,9 +23,7 @@ describe('ast', function() {
|
||||
|
||||
describe('MustacheStatement', function() {
|
||||
it('should store args', function() {
|
||||
var id = {isSimple: true},
|
||||
hash = {},
|
||||
mustache = new handlebarsEnv.AST.MustacheStatement({}, null, null, true, {}, LOCATION_INFO);
|
||||
var mustache = new handlebarsEnv.AST.MustacheStatement({}, null, null, true, {}, LOCATION_INFO);
|
||||
equals(mustache.type, 'MustacheStatement');
|
||||
equals(mustache.escaped, true);
|
||||
testLocationInfoStorage(mustache);
|
||||
@@ -35,11 +32,11 @@ describe('ast', function() {
|
||||
describe('BlockStatement', function() {
|
||||
it('should throw on mustache mismatch', function() {
|
||||
shouldThrow(function() {
|
||||
handlebarsEnv.parse("\n {{#foo}}{{/bar}}");
|
||||
handlebarsEnv.parse('\n {{#foo}}{{/bar}}');
|
||||
}, Handlebars.Exception, "foo doesn't match bar - 2:5");
|
||||
});
|
||||
|
||||
it('stores location info', function(){
|
||||
it('stores location info', function() {
|
||||
var mustacheNode = new handlebarsEnv.AST.MustacheStatement([{ original: 'foo'}], null, null, false, {});
|
||||
var block = new handlebarsEnv.AST.BlockStatement(
|
||||
mustacheNode,
|
||||
@@ -54,114 +51,114 @@ describe('ast', function() {
|
||||
});
|
||||
});
|
||||
describe('PathExpression', function() {
|
||||
it('stores location info', function(){
|
||||
it('stores location info', function() {
|
||||
var idNode = new handlebarsEnv.AST.PathExpression(false, 0, [], 'foo', LOCATION_INFO);
|
||||
testLocationInfoStorage(idNode);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Hash', function(){
|
||||
it('stores location info', function(){
|
||||
describe('Hash', function() {
|
||||
it('stores location info', function() {
|
||||
var hash = new handlebarsEnv.AST.Hash([], LOCATION_INFO);
|
||||
testLocationInfoStorage(hash);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ContentStatement', function(){
|
||||
it('stores location info', function(){
|
||||
var content = new handlebarsEnv.AST.ContentStatement("HI", LOCATION_INFO);
|
||||
describe('ContentStatement', function() {
|
||||
it('stores location info', function() {
|
||||
var content = new handlebarsEnv.AST.ContentStatement('HI', LOCATION_INFO);
|
||||
testLocationInfoStorage(content);
|
||||
});
|
||||
});
|
||||
|
||||
describe('CommentStatement', function(){
|
||||
it('stores location info', function(){
|
||||
var comment = new handlebarsEnv.AST.CommentStatement("HI", {}, LOCATION_INFO);
|
||||
describe('CommentStatement', function() {
|
||||
it('stores location info', function() {
|
||||
var comment = new handlebarsEnv.AST.CommentStatement('HI', {}, LOCATION_INFO);
|
||||
testLocationInfoStorage(comment);
|
||||
});
|
||||
});
|
||||
|
||||
describe('NumberLiteral', function(){
|
||||
it('stores location info', function(){
|
||||
var integer = new handlebarsEnv.AST.NumberLiteral("6", LOCATION_INFO);
|
||||
describe('NumberLiteral', function() {
|
||||
it('stores location info', function() {
|
||||
var integer = new handlebarsEnv.AST.NumberLiteral('6', LOCATION_INFO);
|
||||
testLocationInfoStorage(integer);
|
||||
});
|
||||
});
|
||||
|
||||
describe('StringLiteral', function(){
|
||||
it('stores location info', function(){
|
||||
var string = new handlebarsEnv.AST.StringLiteral("6", LOCATION_INFO);
|
||||
describe('StringLiteral', function() {
|
||||
it('stores location info', function() {
|
||||
var string = new handlebarsEnv.AST.StringLiteral('6', LOCATION_INFO);
|
||||
testLocationInfoStorage(string);
|
||||
});
|
||||
});
|
||||
|
||||
describe('BooleanLiteral', function(){
|
||||
it('stores location info', function(){
|
||||
var bool = new handlebarsEnv.AST.BooleanLiteral("true", LOCATION_INFO);
|
||||
describe('BooleanLiteral', function() {
|
||||
it('stores location info', function() {
|
||||
var bool = new handlebarsEnv.AST.BooleanLiteral('true', LOCATION_INFO);
|
||||
testLocationInfoStorage(bool);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PartialStatement', function(){
|
||||
it('stores location info', function(){
|
||||
describe('PartialStatement', function() {
|
||||
it('stores location info', function() {
|
||||
var pn = new handlebarsEnv.AST.PartialStatement('so_partial', [], {}, {}, LOCATION_INFO);
|
||||
testLocationInfoStorage(pn);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Program', function(){
|
||||
it('storing location info', function(){
|
||||
describe('Program', function() {
|
||||
it('storing location info', function() {
|
||||
var pn = new handlebarsEnv.AST.Program([], null, {}, LOCATION_INFO);
|
||||
testLocationInfoStorage(pn);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Line Numbers", function(){
|
||||
describe('Line Numbers', function() {
|
||||
var ast, body;
|
||||
|
||||
function testColumns(node, firstLine, lastLine, firstColumn, lastColumn){
|
||||
function testColumns(node, firstLine, lastLine, firstColumn, lastColumn) {
|
||||
equals(node.loc.start.line, firstLine);
|
||||
equals(node.loc.start.column, firstColumn);
|
||||
equals(node.loc.end.line, lastLine);
|
||||
equals(node.loc.end.column, lastColumn);
|
||||
}
|
||||
|
||||
ast = Handlebars.parse("line 1 {{line1Token}}\n line 2 {{line2token}}\n line 3 {{#blockHelperOnLine3}}\nline 4{{line4token}}\n" +
|
||||
"line5{{else}}\n{{line6Token}}\n{{/blockHelperOnLine3}}");
|
||||
ast = Handlebars.parse('line 1 {{line1Token}}\n line 2 {{line2token}}\n line 3 {{#blockHelperOnLine3}}\nline 4{{line4token}}\n' +
|
||||
'line5{{else}}\n{{line6Token}}\n{{/blockHelperOnLine3}}');
|
||||
body = ast.body;
|
||||
|
||||
it('gets ContentNode line numbers', function(){
|
||||
it('gets ContentNode line numbers', function() {
|
||||
var contentNode = body[0];
|
||||
testColumns(contentNode, 1, 1, 0, 7);
|
||||
});
|
||||
|
||||
it('gets MustacheStatement line numbers', function(){
|
||||
it('gets MustacheStatement line numbers', function() {
|
||||
var mustacheNode = body[1];
|
||||
testColumns(mustacheNode, 1, 1, 7, 21);
|
||||
});
|
||||
|
||||
it('gets line numbers correct when newlines appear', function(){
|
||||
it('gets line numbers correct when newlines appear', function() {
|
||||
testColumns(body[2], 1, 2, 21, 8);
|
||||
});
|
||||
|
||||
it('gets MustacheStatement line numbers correct across newlines', function(){
|
||||
it('gets MustacheStatement line numbers correct across newlines', function() {
|
||||
var secondMustacheStatement = body[3];
|
||||
testColumns(secondMustacheStatement, 2, 2, 8, 22);
|
||||
});
|
||||
|
||||
it('gets the block helper information correct', function(){
|
||||
it('gets the block helper information correct', function() {
|
||||
var blockHelperNode = body[5];
|
||||
testColumns(blockHelperNode, 3, 7, 8, 23);
|
||||
});
|
||||
|
||||
it('correctly records the line numbers the program of a block helper', function(){
|
||||
it('correctly records the line numbers the program of a block helper', function() {
|
||||
var blockHelperNode = body[5],
|
||||
program = blockHelperNode.program;
|
||||
|
||||
testColumns(program, 3, 5, 8, 5);
|
||||
});
|
||||
|
||||
it('correctly records the line numbers of an inverse of a block helper', function(){
|
||||
it('correctly records the line numbers of an inverse of a block helper', function() {
|
||||
var blockHelperNode = body[5],
|
||||
inverse = blockHelperNode.inverse;
|
||||
|
||||
@@ -169,7 +166,7 @@ describe('ast', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('standalone flags', function(){
|
||||
describe('standalone flags', function() {
|
||||
describe('mustache', function() {
|
||||
it('does not mark mustaches as standalone', function() {
|
||||
var ast = Handlebars.parse(' {{comment}} ');
|
||||
|
||||
+119
-118
@@ -1,38 +1,37 @@
|
||||
/*global CompilerContext, Handlebars, beforeEach, shouldCompileTo, shouldThrow */
|
||||
global.handlebarsEnv = null;
|
||||
|
||||
beforeEach(function() {
|
||||
global.handlebarsEnv = Handlebars.create();
|
||||
});
|
||||
|
||||
describe("basic context", function() {
|
||||
it("most basic", function() {
|
||||
shouldCompileTo("{{foo}}", { foo: "foo" }, "foo");
|
||||
describe('basic context', function() {
|
||||
it('most basic', function() {
|
||||
shouldCompileTo('{{foo}}', { foo: 'foo' }, 'foo');
|
||||
});
|
||||
|
||||
it("escaping", function() {
|
||||
shouldCompileTo("\\{{foo}}", { foo: "food" }, "{{foo}}");
|
||||
shouldCompileTo("content \\{{foo}}", { foo: "food" }, "content {{foo}}");
|
||||
shouldCompileTo("\\\\{{foo}}", { foo: "food" }, "\\food");
|
||||
shouldCompileTo("content \\\\{{foo}}", { foo: "food" }, "content \\food");
|
||||
shouldCompileTo("\\\\ {{foo}}", { foo: "food" }, "\\\\ food");
|
||||
it('escaping', function() {
|
||||
shouldCompileTo('\\{{foo}}', { foo: 'food' }, '{{foo}}');
|
||||
shouldCompileTo('content \\{{foo}}', { foo: 'food' }, 'content {{foo}}');
|
||||
shouldCompileTo('\\\\{{foo}}', { foo: 'food' }, '\\food');
|
||||
shouldCompileTo('content \\\\{{foo}}', { foo: 'food' }, 'content \\food');
|
||||
shouldCompileTo('\\\\ {{foo}}', { foo: 'food' }, '\\\\ food');
|
||||
});
|
||||
|
||||
it("compiling with a basic context", function() {
|
||||
shouldCompileTo("Goodbye\n{{cruel}}\n{{world}}!", {cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!",
|
||||
"It works if all the required keys are provided");
|
||||
it('compiling with a basic context', function() {
|
||||
shouldCompileTo('Goodbye\n{{cruel}}\n{{world}}!', {cruel: 'cruel', world: 'world'}, 'Goodbye\ncruel\nworld!',
|
||||
'It works if all the required keys are provided');
|
||||
});
|
||||
|
||||
it("compiling with an undefined context", function() {
|
||||
shouldCompileTo("Goodbye\n{{cruel}}\n{{world.bar}}!", undefined, "Goodbye\n\n!");
|
||||
it('compiling with an undefined context', function() {
|
||||
shouldCompileTo('Goodbye\n{{cruel}}\n{{world.bar}}!', undefined, 'Goodbye\n\n!');
|
||||
|
||||
shouldCompileTo("{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}", undefined, "Goodbye");
|
||||
shouldCompileTo('{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}', undefined, 'Goodbye');
|
||||
});
|
||||
|
||||
it("comments", function() {
|
||||
shouldCompileTo("{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!",
|
||||
{cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!",
|
||||
"comments are ignored");
|
||||
it('comments', function() {
|
||||
shouldCompileTo('{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!',
|
||||
{cruel: 'cruel', world: 'world'}, 'Goodbye\ncruel\nworld!',
|
||||
'comments are ignored');
|
||||
|
||||
shouldCompileTo(' {{~! comment ~}} blah', {}, 'blah');
|
||||
shouldCompileTo(' {{~!-- long-comment --~}} blah', {}, 'blah');
|
||||
@@ -42,28 +41,30 @@ describe("basic context", function() {
|
||||
shouldCompileTo(' {{~!-- long-comment --}} blah', {}, ' blah');
|
||||
});
|
||||
|
||||
it("boolean", function() {
|
||||
var string = "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!";
|
||||
shouldCompileTo(string, {goodbye: true, world: "world"}, "GOODBYE cruel world!",
|
||||
"booleans show the contents when true");
|
||||
it('boolean', function() {
|
||||
var string = '{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!';
|
||||
shouldCompileTo(string, {goodbye: true, world: 'world'}, 'GOODBYE cruel world!',
|
||||
'booleans show the contents when true');
|
||||
|
||||
shouldCompileTo(string, {goodbye: false, world: "world"}, "cruel world!",
|
||||
"booleans do not show the contents when false");
|
||||
shouldCompileTo(string, {goodbye: false, world: 'world'}, 'cruel world!',
|
||||
'booleans do not show the contents when false');
|
||||
});
|
||||
|
||||
it("zeros", function() {
|
||||
shouldCompileTo("num1: {{num1}}, num2: {{num2}}", {num1: 42, num2: 0},
|
||||
"num1: 42, num2: 0");
|
||||
shouldCompileTo("num: {{.}}", 0, "num: 0");
|
||||
shouldCompileTo("num: {{num1/num2}}", {num1: {num2: 0}}, "num: 0");
|
||||
it('zeros', function() {
|
||||
shouldCompileTo('num1: {{num1}}, num2: {{num2}}', {num1: 42, num2: 0},
|
||||
'num1: 42, num2: 0');
|
||||
shouldCompileTo('num: {{.}}', 0, 'num: 0');
|
||||
shouldCompileTo('num: {{num1/num2}}', {num1: {num2: 0}}, 'num: 0');
|
||||
});
|
||||
it('false', function() {
|
||||
/*eslint-disable no-new-wrappers */
|
||||
shouldCompileTo('val1: {{val1}}, val2: {{val2}}', {val1: false, val2: new Boolean(false)}, 'val1: false, val2: false');
|
||||
shouldCompileTo('val: {{.}}', false, 'val: false');
|
||||
shouldCompileTo('val: {{val1/val2}}', {val1: {val2: false}}, 'val: false');
|
||||
|
||||
shouldCompileTo('val1: {{{val1}}}, val2: {{{val2}}}', {val1: false, val2: new Boolean(false)}, 'val1: false, val2: false');
|
||||
shouldCompileTo('val: {{{val1/val2}}}', {val1: {val2: false}}, 'val: false');
|
||||
/*eslint-enable */
|
||||
});
|
||||
|
||||
it('should handle undefined and null', function() {
|
||||
@@ -90,143 +91,143 @@ describe("basic context", function() {
|
||||
'null!');
|
||||
});
|
||||
|
||||
it("newlines", function() {
|
||||
it('newlines', function() {
|
||||
shouldCompileTo("Alan's\nTest", {}, "Alan's\nTest");
|
||||
shouldCompileTo("Alan's\rTest", {}, "Alan's\rTest");
|
||||
});
|
||||
|
||||
it("escaping text", function() {
|
||||
it('escaping text', function() {
|
||||
shouldCompileTo("Awesome's", {}, "Awesome's", "text is escaped so that it doesn't get caught on single quotes");
|
||||
shouldCompileTo("Awesome\\", {}, "Awesome\\", "text is escaped so that the closing quote can't be ignored");
|
||||
shouldCompileTo("Awesome\\\\ foo", {}, "Awesome\\\\ foo", "text is escaped so that it doesn't mess up backslashes");
|
||||
shouldCompileTo("Awesome {{foo}}", {foo: '\\'}, "Awesome \\", "text is escaped so that it doesn't mess up backslashes");
|
||||
shouldCompileTo(' " " ', {}, ' " " ', "double quotes never produce invalid javascript");
|
||||
shouldCompileTo('Awesome\\', {}, 'Awesome\\', "text is escaped so that the closing quote can't be ignored");
|
||||
shouldCompileTo('Awesome\\\\ foo', {}, 'Awesome\\\\ foo', "text is escaped so that it doesn't mess up backslashes");
|
||||
shouldCompileTo('Awesome {{foo}}', {foo: '\\'}, 'Awesome \\', "text is escaped so that it doesn't mess up backslashes");
|
||||
shouldCompileTo(" ' ' ", {}, " ' ' ", 'double quotes never produce invalid javascript');
|
||||
});
|
||||
|
||||
it("escaping expressions", function() {
|
||||
shouldCompileTo("{{{awesome}}}", {awesome: "&\"\\<>"}, '&\"\\<>',
|
||||
it('escaping expressions', function() {
|
||||
shouldCompileTo('{{{awesome}}}', {awesome: '&\'\\<>'}, '&\'\\<>',
|
||||
"expressions with 3 handlebars aren't escaped");
|
||||
|
||||
shouldCompileTo("{{&awesome}}", {awesome: "&\"\\<>"}, '&\"\\<>',
|
||||
shouldCompileTo('{{&awesome}}', {awesome: '&\'\\<>'}, '&\'\\<>',
|
||||
"expressions with {{& handlebars aren't escaped");
|
||||
|
||||
shouldCompileTo("{{awesome}}", {awesome: "&\"'`\\<>"}, '&"'`\\<>',
|
||||
"by default expressions should be escaped");
|
||||
shouldCompileTo('{{awesome}}', {awesome: "&\"'`\\<>"}, '&"'`\\<>',
|
||||
'by default expressions should be escaped');
|
||||
|
||||
shouldCompileTo("{{awesome}}", {awesome: "Escaped, <b> looks like: <b>"}, 'Escaped, <b> looks like: &lt;b&gt;',
|
||||
"escaping should properly handle amperstands");
|
||||
shouldCompileTo('{{awesome}}', {awesome: 'Escaped, <b> looks like: <b>'}, 'Escaped, <b> looks like: &lt;b&gt;',
|
||||
'escaping should properly handle amperstands');
|
||||
});
|
||||
|
||||
it("functions returning safestrings shouldn't be escaped", function() {
|
||||
var hash = {awesome: function() { return new Handlebars.SafeString("&\"\\<>"); }};
|
||||
shouldCompileTo("{{awesome}}", hash, '&\"\\<>',
|
||||
var hash = {awesome: function() { return new Handlebars.SafeString('&\'\\<>'); }};
|
||||
shouldCompileTo('{{awesome}}', hash, '&\'\\<>',
|
||||
"functions returning safestrings aren't escaped");
|
||||
});
|
||||
|
||||
it("functions", function() {
|
||||
shouldCompileTo("{{awesome}}", {awesome: function() { return "Awesome"; }}, "Awesome",
|
||||
"functions are called and render their output");
|
||||
shouldCompileTo("{{awesome}}", {awesome: function() { return this.more; }, more: "More awesome"}, "More awesome",
|
||||
"functions are bound to the context");
|
||||
it('functions', function() {
|
||||
shouldCompileTo('{{awesome}}', {awesome: function() { return 'Awesome'; }}, 'Awesome',
|
||||
'functions are called and render their output');
|
||||
shouldCompileTo('{{awesome}}', {awesome: function() { return this.more; }, more: 'More awesome'}, 'More awesome',
|
||||
'functions are bound to the context');
|
||||
});
|
||||
|
||||
it("functions with context argument", function() {
|
||||
shouldCompileTo("{{awesome frank}}",
|
||||
it('functions with context argument', function() {
|
||||
shouldCompileTo('{{awesome frank}}',
|
||||
{awesome: function(context) { return context; },
|
||||
frank: "Frank"},
|
||||
"Frank", "functions are called with context arguments");
|
||||
frank: 'Frank'},
|
||||
'Frank', 'functions are called with context arguments');
|
||||
});
|
||||
it("pathed functions with context argument", function() {
|
||||
shouldCompileTo("{{bar.awesome frank}}",
|
||||
it('pathed functions with context argument', function() {
|
||||
shouldCompileTo('{{bar.awesome frank}}',
|
||||
{bar: {awesome: function(context) { return context; }},
|
||||
frank: "Frank"},
|
||||
"Frank", "functions are called with context arguments");
|
||||
frank: 'Frank'},
|
||||
'Frank', 'functions are called with context arguments');
|
||||
});
|
||||
it("depthed functions with context argument", function() {
|
||||
shouldCompileTo("{{#with frank}}{{../awesome .}}{{/with}}",
|
||||
it('depthed functions with context argument', function() {
|
||||
shouldCompileTo('{{#with frank}}{{../awesome .}}{{/with}}',
|
||||
{awesome: function(context) { return context; },
|
||||
frank: "Frank"},
|
||||
"Frank", "functions are called with context arguments");
|
||||
frank: 'Frank'},
|
||||
'Frank', 'functions are called with context arguments');
|
||||
});
|
||||
|
||||
it("block functions with context argument", function() {
|
||||
shouldCompileTo("{{#awesome 1}}inner {{.}}{{/awesome}}",
|
||||
it('block functions with context argument', function() {
|
||||
shouldCompileTo('{{#awesome 1}}inner {{.}}{{/awesome}}',
|
||||
{awesome: function(context, options) { return options.fn(context); }},
|
||||
"inner 1", "block functions are called with context and options");
|
||||
'inner 1', 'block functions are called with context and options');
|
||||
});
|
||||
|
||||
it("depthed block functions with context argument", function() {
|
||||
shouldCompileTo("{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}",
|
||||
it('depthed block functions with context argument', function() {
|
||||
shouldCompileTo('{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}',
|
||||
{value: true, awesome: function(context, options) { return options.fn(context); }},
|
||||
"inner 1", "block functions are called with context and options");
|
||||
'inner 1', 'block functions are called with context and options');
|
||||
});
|
||||
|
||||
it("block functions without context argument", function() {
|
||||
shouldCompileTo("{{#awesome}}inner{{/awesome}}",
|
||||
it('block functions without context argument', function() {
|
||||
shouldCompileTo('{{#awesome}}inner{{/awesome}}',
|
||||
{awesome: function(options) { return options.fn(this); }},
|
||||
"inner", "block functions are called with options");
|
||||
'inner', 'block functions are called with options');
|
||||
});
|
||||
it("pathed block functions without context argument", function() {
|
||||
shouldCompileTo("{{#foo.awesome}}inner{{/foo.awesome}}",
|
||||
it('pathed block functions without context argument', function() {
|
||||
shouldCompileTo('{{#foo.awesome}}inner{{/foo.awesome}}',
|
||||
{foo: {awesome: function() { return this; }}},
|
||||
"inner", "block functions are called with options");
|
||||
'inner', 'block functions are called with options');
|
||||
});
|
||||
it("depthed block functions without context argument", function() {
|
||||
shouldCompileTo("{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}",
|
||||
it('depthed block functions without context argument', function() {
|
||||
shouldCompileTo('{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}',
|
||||
{value: true, awesome: function() { return this; }},
|
||||
"inner", "block functions are called with options");
|
||||
'inner', 'block functions are called with options');
|
||||
});
|
||||
|
||||
|
||||
it("paths with hyphens", function() {
|
||||
shouldCompileTo("{{foo-bar}}", {"foo-bar": "baz"}, "baz", "Paths can contain hyphens (-)");
|
||||
shouldCompileTo("{{foo.foo-bar}}", {foo: {"foo-bar": "baz"}}, "baz", "Paths can contain hyphens (-)");
|
||||
shouldCompileTo("{{foo/foo-bar}}", {foo: {"foo-bar": "baz"}}, "baz", "Paths can contain hyphens (-)");
|
||||
it('paths with hyphens', function() {
|
||||
shouldCompileTo('{{foo-bar}}', {'foo-bar': 'baz'}, 'baz', 'Paths can contain hyphens (-)');
|
||||
shouldCompileTo('{{foo.foo-bar}}', {foo: {'foo-bar': 'baz'}}, 'baz', 'Paths can contain hyphens (-)');
|
||||
shouldCompileTo('{{foo/foo-bar}}', {foo: {'foo-bar': 'baz'}}, 'baz', 'Paths can contain hyphens (-)');
|
||||
});
|
||||
|
||||
it("nested paths", function() {
|
||||
shouldCompileTo("Goodbye {{alan/expression}} world!", {alan: {expression: "beautiful"}},
|
||||
"Goodbye beautiful world!", "Nested paths access nested objects");
|
||||
it('nested paths', function() {
|
||||
shouldCompileTo('Goodbye {{alan/expression}} world!', {alan: {expression: 'beautiful'}},
|
||||
'Goodbye beautiful world!', 'Nested paths access nested objects');
|
||||
});
|
||||
|
||||
it("nested paths with empty string value", function() {
|
||||
shouldCompileTo("Goodbye {{alan/expression}} world!", {alan: {expression: ""}},
|
||||
"Goodbye world!", "Nested paths access nested objects with empty string");
|
||||
it('nested paths with empty string value', function() {
|
||||
shouldCompileTo('Goodbye {{alan/expression}} world!', {alan: {expression: ''}},
|
||||
'Goodbye world!', 'Nested paths access nested objects with empty string');
|
||||
});
|
||||
|
||||
it("literal paths", function() {
|
||||
shouldCompileTo("Goodbye {{[@alan]/expression}} world!", {"@alan": {expression: "beautiful"}},
|
||||
"Goodbye beautiful world!", "Literal paths can be used");
|
||||
shouldCompileTo("Goodbye {{[foo bar]/expression}} world!", {"foo bar": {expression: "beautiful"}},
|
||||
"Goodbye beautiful world!", "Literal paths can be used");
|
||||
it('literal paths', function() {
|
||||
shouldCompileTo('Goodbye {{[@alan]/expression}} world!', {'@alan': {expression: 'beautiful'}},
|
||||
'Goodbye beautiful world!', 'Literal paths can be used');
|
||||
shouldCompileTo('Goodbye {{[foo bar]/expression}} world!', {'foo bar': {expression: 'beautiful'}},
|
||||
'Goodbye beautiful world!', 'Literal paths can be used');
|
||||
});
|
||||
|
||||
it('literal references', function() {
|
||||
shouldCompileTo("Goodbye {{[foo bar]}} world!", {"foo bar": "beautiful"},
|
||||
"Goodbye beautiful world!", "Literal paths can be used");
|
||||
shouldCompileTo('Goodbye {{[foo bar]}} world!', {'foo bar': 'beautiful'},
|
||||
'Goodbye beautiful world!', 'Literal paths can be used');
|
||||
});
|
||||
|
||||
it("that current context path ({{.}}) doesn't hit helpers", function() {
|
||||
shouldCompileTo("test: {{.}}", [null, {helper: "awesome"}], "test: ");
|
||||
shouldCompileTo('test: {{.}}', [null, {helper: 'awesome'}], 'test: ');
|
||||
});
|
||||
|
||||
it("complex but empty paths", function() {
|
||||
shouldCompileTo("{{person/name}}", {person: {name: null}}, "");
|
||||
shouldCompileTo("{{person/name}}", {person: {}}, "");
|
||||
it('complex but empty paths', function() {
|
||||
shouldCompileTo('{{person/name}}', {person: {name: null}}, '');
|
||||
shouldCompileTo('{{person/name}}', {person: {}}, '');
|
||||
});
|
||||
|
||||
it("this keyword in paths", function() {
|
||||
var string = "{{#goodbyes}}{{this}}{{/goodbyes}}";
|
||||
var hash = {goodbyes: ["goodbye", "Goodbye", "GOODBYE"]};
|
||||
shouldCompileTo(string, hash, "goodbyeGoodbyeGOODBYE",
|
||||
"This keyword in paths evaluates to current context");
|
||||
it('this keyword in paths', function() {
|
||||
var string = '{{#goodbyes}}{{this}}{{/goodbyes}}';
|
||||
var hash = {goodbyes: ['goodbye', 'Goodbye', 'GOODBYE']};
|
||||
shouldCompileTo(string, hash, 'goodbyeGoodbyeGOODBYE',
|
||||
'This keyword in paths evaluates to current context');
|
||||
|
||||
string = "{{#hellos}}{{this/text}}{{/hellos}}";
|
||||
hash = {hellos: [{text: "hello"}, {text: "Hello"}, {text: "HELLO"}]};
|
||||
shouldCompileTo(string, hash, "helloHelloHELLO", "This keyword evaluates in more complex paths");
|
||||
string = '{{#hellos}}{{this/text}}{{/hellos}}';
|
||||
hash = {hellos: [{text: 'hello'}, {text: 'Hello'}, {text: 'HELLO'}]};
|
||||
shouldCompileTo(string, hash, 'helloHelloHELLO', 'This keyword evaluates in more complex paths');
|
||||
});
|
||||
|
||||
it("this keyword nested inside path", function() {
|
||||
it('this keyword nested inside path', function() {
|
||||
shouldThrow(function() {
|
||||
CompilerContext.compile('{{#hellos}}{{text/this/foo}}{{/hellos}}');
|
||||
}, Error, 'Invalid path: text/this - 1:13');
|
||||
@@ -235,22 +236,22 @@ describe("basic context", function() {
|
||||
shouldCompileTo('{{text/[this]}}', {text: {'this': 'bar'}}, 'bar');
|
||||
});
|
||||
|
||||
it("this keyword in helpers", function() {
|
||||
it('this keyword in helpers', function() {
|
||||
var helpers = {foo: function(value) {
|
||||
return 'bar ' + value;
|
||||
}};
|
||||
var string = "{{#goodbyes}}{{foo this}}{{/goodbyes}}";
|
||||
var hash = {goodbyes: ["goodbye", "Goodbye", "GOODBYE"]};
|
||||
shouldCompileTo(string, [hash, helpers], "bar goodbyebar Goodbyebar GOODBYE",
|
||||
"This keyword in paths evaluates to current context");
|
||||
var string = '{{#goodbyes}}{{foo this}}{{/goodbyes}}';
|
||||
var hash = {goodbyes: ['goodbye', 'Goodbye', 'GOODBYE']};
|
||||
shouldCompileTo(string, [hash, helpers], 'bar goodbyebar Goodbyebar GOODBYE',
|
||||
'This keyword in paths evaluates to current context');
|
||||
|
||||
string = "{{#hellos}}{{foo this/text}}{{/hellos}}";
|
||||
hash = {hellos: [{text: "hello"}, {text: "Hello"}, {text: "HELLO"}]};
|
||||
shouldCompileTo(string, [hash, helpers], "bar hellobar Hellobar HELLO", "This keyword evaluates in more complex paths");
|
||||
string = '{{#hellos}}{{foo this/text}}{{/hellos}}';
|
||||
hash = {hellos: [{text: 'hello'}, {text: 'Hello'}, {text: 'HELLO'}]};
|
||||
shouldCompileTo(string, [hash, helpers], 'bar hellobar Hellobar HELLO', 'This keyword evaluates in more complex paths');
|
||||
});
|
||||
|
||||
it("this keyword nested inside helpers param", function() {
|
||||
var string = "{{#hellos}}{{foo text/this/foo}}{{/hellos}}";
|
||||
it('this keyword nested inside helpers param', function() {
|
||||
var string = '{{#hellos}}{{foo text/this/foo}}{{/hellos}}';
|
||||
shouldThrow(function() {
|
||||
CompilerContext.compile(string);
|
||||
}, Error, 'Invalid path: text/this - 1:17');
|
||||
|
||||
+73
-74
@@ -1,112 +1,111 @@
|
||||
/*global CompilerContext, shouldCompileTo, shouldThrow */
|
||||
describe('blocks', function() {
|
||||
it("array", function() {
|
||||
var string = "{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!";
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!",
|
||||
"Arrays iterate over the contents when not empty");
|
||||
it('array', function() {
|
||||
var string = '{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!',
|
||||
'Arrays iterate over the contents when not empty');
|
||||
|
||||
shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
|
||||
"Arrays ignore the contents when empty");
|
||||
shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
|
||||
'Arrays ignore the contents when empty');
|
||||
});
|
||||
|
||||
it('array without data', function() {
|
||||
var string = '{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
shouldCompileTo(string, [hash,,,,false], 'goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE');
|
||||
var string = '{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
shouldCompileTo(string, [hash,,, false], 'goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE');
|
||||
});
|
||||
|
||||
it("array with @index", function() {
|
||||
var string = "{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!";
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
it('array with @index', function() {
|
||||
var string = '{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
equal(result, "0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!", "The @index variable is used");
|
||||
});
|
||||
|
||||
it("empty block", function() {
|
||||
var string = "{{#goodbyes}}{{/goodbyes}}cruel {{world}}!";
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
shouldCompileTo(string, hash, "cruel world!",
|
||||
"Arrays iterate over the contents when not empty");
|
||||
|
||||
shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
|
||||
"Arrays ignore the contents when empty");
|
||||
equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used');
|
||||
});
|
||||
|
||||
it("block with complex lookup", function() {
|
||||
var string = "{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}";
|
||||
var hash = {name: "Alan", goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}]};
|
||||
it('empty block', function() {
|
||||
var string = '{{#goodbyes}}{{/goodbyes}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
shouldCompileTo(string, hash, 'cruel world!',
|
||||
'Arrays iterate over the contents when not empty');
|
||||
|
||||
shouldCompileTo(string, hash, "goodbye cruel Alan! Goodbye cruel Alan! GOODBYE cruel Alan! ",
|
||||
"Templates can access variables in contexts up the stack with relative path syntax");
|
||||
shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
|
||||
'Arrays ignore the contents when empty');
|
||||
});
|
||||
|
||||
it('block with complex lookup', function() {
|
||||
var string = '{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}';
|
||||
var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]};
|
||||
|
||||
shouldCompileTo(string, hash, 'goodbye cruel Alan! Goodbye cruel Alan! GOODBYE cruel Alan! ',
|
||||
'Templates can access variables in contexts up the stack with relative path syntax');
|
||||
});
|
||||
|
||||
it('multiple blocks with complex lookup', function() {
|
||||
var string = '{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}';
|
||||
var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]};
|
||||
var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]};
|
||||
|
||||
shouldCompileTo(string, hash, 'AlanAlanAlanAlanAlanAlan');
|
||||
});
|
||||
|
||||
it("block with complex lookup using nested context", function() {
|
||||
var string = "{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}";
|
||||
it('block with complex lookup using nested context', function() {
|
||||
var string = '{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}';
|
||||
|
||||
shouldThrow(function() {
|
||||
CompilerContext.compile(string);
|
||||
}, Error);
|
||||
});
|
||||
|
||||
it("block with deep nested complex lookup", function() {
|
||||
var string = "{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}";
|
||||
var hash = {omg: "OMG!", outer: [{ sibling: 'sad', inner: [{ text: "goodbye" }] }] };
|
||||
it('block with deep nested complex lookup', function() {
|
||||
var string = '{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}';
|
||||
var hash = {omg: 'OMG!', outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }] };
|
||||
|
||||
shouldCompileTo(string, hash, "Goodbye cruel sad OMG!");
|
||||
shouldCompileTo(string, hash, 'Goodbye cruel sad OMG!');
|
||||
});
|
||||
|
||||
describe('inverted sections', function() {
|
||||
it("inverted sections with unset value", function() {
|
||||
var string = "{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}";
|
||||
it('inverted sections with unset value', function() {
|
||||
var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
||||
var hash = {};
|
||||
shouldCompileTo(string, hash, "Right On!", "Inverted section rendered when value isn't set.");
|
||||
shouldCompileTo(string, hash, 'Right On!', "Inverted section rendered when value isn't set.");
|
||||
});
|
||||
|
||||
it("inverted section with false value", function() {
|
||||
var string = "{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}";
|
||||
it('inverted section with false value', function() {
|
||||
var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
||||
var hash = {goodbyes: false};
|
||||
shouldCompileTo(string, hash, "Right On!", "Inverted section rendered when value is false.");
|
||||
shouldCompileTo(string, hash, 'Right On!', 'Inverted section rendered when value is false.');
|
||||
});
|
||||
|
||||
it("inverted section with empty set", function() {
|
||||
var string = "{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}";
|
||||
it('inverted section with empty set', function() {
|
||||
var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
||||
var hash = {goodbyes: []};
|
||||
shouldCompileTo(string, hash, "Right On!", "Inverted section rendered when value is empty set.");
|
||||
shouldCompileTo(string, hash, 'Right On!', 'Inverted section rendered when value is empty set.');
|
||||
});
|
||||
|
||||
it("block inverted sections", function() {
|
||||
shouldCompileTo("{{#people}}{{name}}{{^}}{{none}}{{/people}}", {none: "No people"},
|
||||
"No people");
|
||||
it('block inverted sections', function() {
|
||||
shouldCompileTo('{{#people}}{{name}}{{^}}{{none}}{{/people}}', {none: 'No people'},
|
||||
'No people');
|
||||
});
|
||||
it("chained inverted sections", function() {
|
||||
shouldCompileTo("{{#people}}{{name}}{{else if none}}{{none}}{{/people}}", {none: "No people"},
|
||||
"No people");
|
||||
shouldCompileTo("{{#people}}{{name}}{{else if nothere}}fail{{else unless nothere}}{{none}}{{/people}}", {none: "No people"},
|
||||
"No people");
|
||||
shouldCompileTo("{{#people}}{{name}}{{else if none}}{{none}}{{else}}fail{{/people}}", {none: "No people"},
|
||||
"No people");
|
||||
it('chained inverted sections', function() {
|
||||
shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{/people}}', {none: 'No people'},
|
||||
'No people');
|
||||
shouldCompileTo('{{#people}}{{name}}{{else if nothere}}fail{{else unless nothere}}{{none}}{{/people}}', {none: 'No people'},
|
||||
'No people');
|
||||
shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{else}}fail{{/people}}', {none: 'No people'},
|
||||
'No people');
|
||||
});
|
||||
it("chained inverted sections with mismatch", function() {
|
||||
it('chained inverted sections with mismatch', function() {
|
||||
shouldThrow(function() {
|
||||
shouldCompileTo("{{#people}}{{name}}{{else if none}}{{none}}{{/if}}", {none: "No people"},
|
||||
"No people");
|
||||
shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{/if}}', {none: 'No people'},
|
||||
'No people');
|
||||
}, Error);
|
||||
});
|
||||
|
||||
it("block inverted sections with empty arrays", function() {
|
||||
shouldCompileTo("{{#people}}{{name}}{{^}}{{none}}{{/people}}", {none: "No people", people: []},
|
||||
"No people");
|
||||
it('block inverted sections with empty arrays', function() {
|
||||
shouldCompileTo('{{#people}}{{name}}{{^}}{{none}}{{/people}}', {none: 'No people', people: []},
|
||||
'No people');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -131,23 +130,23 @@ describe('blocks', function() {
|
||||
});
|
||||
|
||||
describe('compat mode', function() {
|
||||
it("block with deep recursive lookup lookup", function() {
|
||||
var string = "{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}";
|
||||
var hash = {omg: "OMG!", outer: [{ inner: [{ text: "goodbye" }] }] };
|
||||
it('block with deep recursive lookup lookup', function() {
|
||||
var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}';
|
||||
var hash = {omg: 'OMG!', outer: [{ inner: [{ text: 'goodbye' }] }] };
|
||||
|
||||
shouldCompileTo(string, [hash, undefined, undefined, true], "Goodbye cruel OMG!");
|
||||
shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel OMG!');
|
||||
});
|
||||
it("block with deep recursive pathed lookup", function() {
|
||||
var string = "{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}";
|
||||
var hash = {omg: {yes: "OMG!"}, outer: [{ inner: [{ yes: 'no', text: "goodbye" }] }] };
|
||||
it('block with deep recursive pathed lookup', function() {
|
||||
var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
|
||||
var hash = {omg: {yes: 'OMG!'}, outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] };
|
||||
|
||||
shouldCompileTo(string, [hash, undefined, undefined, true], "Goodbye cruel OMG!");
|
||||
shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel OMG!');
|
||||
});
|
||||
it("block with missed recursive lookup", function() {
|
||||
var string = "{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}";
|
||||
var hash = {omg: {no: "OMG!"}, outer: [{ inner: [{ yes: 'no', text: "goodbye" }] }] };
|
||||
it('block with missed recursive lookup', function() {
|
||||
var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
|
||||
var hash = {omg: {no: 'OMG!'}, outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] };
|
||||
|
||||
shouldCompileTo(string, [hash, undefined, undefined, true], "Goodbye cruel ");
|
||||
shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel ');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+143
-142
@@ -1,52 +1,51 @@
|
||||
/*global CompilerContext, shouldCompileTo, shouldThrow, compileWithPartials, handlebarsEnv */
|
||||
describe('builtin helpers', function() {
|
||||
describe('#if', function() {
|
||||
it("if", function() {
|
||||
var string = "{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!";
|
||||
shouldCompileTo(string, {goodbye: true, world: "world"}, "GOODBYE cruel world!",
|
||||
"if with boolean argument shows the contents when true");
|
||||
shouldCompileTo(string, {goodbye: "dummy", world: "world"}, "GOODBYE cruel world!",
|
||||
"if with string argument shows the contents");
|
||||
shouldCompileTo(string, {goodbye: false, world: "world"}, "cruel world!",
|
||||
"if with boolean argument does not show the contents when false");
|
||||
shouldCompileTo(string, {world: "world"}, "cruel world!",
|
||||
"if with undefined does not show the contents");
|
||||
shouldCompileTo(string, {goodbye: ['foo'], world: "world"}, "GOODBYE cruel world!",
|
||||
"if with non-empty array shows the contents");
|
||||
shouldCompileTo(string, {goodbye: [], world: "world"}, "cruel world!",
|
||||
"if with empty array does not show the contents");
|
||||
shouldCompileTo(string, {goodbye: 0, world: "world"}, "cruel world!",
|
||||
"if with zero does not show the contents");
|
||||
shouldCompileTo("{{#if goodbye includeZero=true}}GOODBYE {{/if}}cruel {{world}}!",
|
||||
{goodbye: 0, world: "world"}, "GOODBYE cruel world!",
|
||||
"if with zero does not show the contents");
|
||||
it('if', function() {
|
||||
var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!';
|
||||
shouldCompileTo(string, {goodbye: true, world: 'world'}, 'GOODBYE cruel world!',
|
||||
'if with boolean argument shows the contents when true');
|
||||
shouldCompileTo(string, {goodbye: 'dummy', world: 'world'}, 'GOODBYE cruel world!',
|
||||
'if with string argument shows the contents');
|
||||
shouldCompileTo(string, {goodbye: false, world: 'world'}, 'cruel world!',
|
||||
'if with boolean argument does not show the contents when false');
|
||||
shouldCompileTo(string, {world: 'world'}, 'cruel world!',
|
||||
'if with undefined does not show the contents');
|
||||
shouldCompileTo(string, {goodbye: ['foo'], world: 'world'}, 'GOODBYE cruel world!',
|
||||
'if with non-empty array shows the contents');
|
||||
shouldCompileTo(string, {goodbye: [], world: 'world'}, 'cruel world!',
|
||||
'if with empty array does not show the contents');
|
||||
shouldCompileTo(string, {goodbye: 0, world: 'world'}, 'cruel world!',
|
||||
'if with zero does not show the contents');
|
||||
shouldCompileTo('{{#if goodbye includeZero=true}}GOODBYE {{/if}}cruel {{world}}!',
|
||||
{goodbye: 0, world: 'world'}, 'GOODBYE cruel world!',
|
||||
'if with zero does not show the contents');
|
||||
});
|
||||
|
||||
it("if with function argument", function() {
|
||||
var string = "{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!";
|
||||
shouldCompileTo(string, {goodbye: function() {return true;}, world: "world"}, "GOODBYE cruel world!",
|
||||
"if with function shows the contents when function returns true");
|
||||
shouldCompileTo(string, {goodbye: function() {return this.world;}, world: "world"}, "GOODBYE cruel world!",
|
||||
"if with function shows the contents when function returns string");
|
||||
shouldCompileTo(string, {goodbye: function() {return false;}, world: "world"}, "cruel world!",
|
||||
"if with function does not show the contents when returns false");
|
||||
shouldCompileTo(string, {goodbye: function() {return this.foo;}, world: "world"}, "cruel world!",
|
||||
"if with function does not show the contents when returns undefined");
|
||||
it('if with function argument', function() {
|
||||
var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!';
|
||||
shouldCompileTo(string, {goodbye: function() {return true; }, world: 'world'}, 'GOODBYE cruel world!',
|
||||
'if with function shows the contents when function returns true');
|
||||
shouldCompileTo(string, {goodbye: function() {return this.world; }, world: 'world'}, 'GOODBYE cruel world!',
|
||||
'if with function shows the contents when function returns string');
|
||||
shouldCompileTo(string, {goodbye: function() {return false; }, world: 'world'}, 'cruel world!',
|
||||
'if with function does not show the contents when returns false');
|
||||
shouldCompileTo(string, {goodbye: function() {return this.foo; }, world: 'world'}, 'cruel world!',
|
||||
'if with function does not show the contents when returns undefined');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#with', function() {
|
||||
it("with", function() {
|
||||
var string = "{{#with person}}{{first}} {{last}}{{/with}}";
|
||||
shouldCompileTo(string, {person: {first: "Alan", last: "Johnson"}}, "Alan Johnson");
|
||||
it('with', function() {
|
||||
var string = '{{#with person}}{{first}} {{last}}{{/with}}';
|
||||
shouldCompileTo(string, {person: {first: 'Alan', last: 'Johnson'}}, 'Alan Johnson');
|
||||
});
|
||||
it("with with function argument", function() {
|
||||
var string = "{{#with person}}{{first}} {{last}}{{/with}}";
|
||||
shouldCompileTo(string, {person: function() { return {first: "Alan", last: "Johnson"};}}, "Alan Johnson");
|
||||
it('with with function argument', function() {
|
||||
var string = '{{#with person}}{{first}} {{last}}{{/with}}';
|
||||
shouldCompileTo(string, {person: function() { return {first: 'Alan', last: 'Johnson'}; }}, 'Alan Johnson');
|
||||
});
|
||||
it("with with else", function() {
|
||||
var string = "{{#with person}}Person is present{{else}}Person is not present{{/with}}";
|
||||
shouldCompileTo(string, {}, "Person is not present");
|
||||
it('with with else', function() {
|
||||
var string = '{{#with person}}Person is present{{else}}Person is not present{{/with}}';
|
||||
shouldCompileTo(string, {}, 'Person is not present');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -57,73 +56,73 @@ describe('builtin helpers', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it("each", function() {
|
||||
var string = "{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!";
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!",
|
||||
"each with array argument iterates over the contents when not empty");
|
||||
shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
|
||||
"each with array argument ignores the contents when empty");
|
||||
it('each', function() {
|
||||
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!',
|
||||
'each with array argument iterates over the contents when not empty');
|
||||
shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
|
||||
'each with array argument ignores the contents when empty');
|
||||
});
|
||||
|
||||
it('each without data', function() {
|
||||
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
shouldCompileTo(string, [hash,,,,false], 'goodbye! Goodbye! GOODBYE! cruel world!');
|
||||
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
shouldCompileTo(string, [hash,,,, false], 'goodbye! Goodbye! GOODBYE! cruel world!');
|
||||
|
||||
hash = {goodbyes: 'cruel', world: 'world'};
|
||||
shouldCompileTo('{{#each .}}{{.}}{{/each}}', [hash,,,,false], 'cruelworld');
|
||||
shouldCompileTo('{{#each .}}{{.}}{{/each}}', [hash,,,, false], 'cruelworld');
|
||||
});
|
||||
|
||||
it('each without context', function() {
|
||||
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
||||
shouldCompileTo(string, [,,,,], 'cruel !');
|
||||
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
||||
shouldCompileTo(string, [,,,, ], 'cruel !');
|
||||
});
|
||||
|
||||
it("each with an object and @key", function() {
|
||||
var string = "{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!";
|
||||
it('each with an object and @key', function() {
|
||||
var string = '{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!';
|
||||
|
||||
function Clazz() {
|
||||
this['<b>#1</b>'] = {text: 'goodbye'};
|
||||
this[2] = {text: 'GOODBYE'};
|
||||
}
|
||||
Clazz.prototype.foo = 'fail';
|
||||
var hash = {goodbyes: new Clazz(), world: 'world'};
|
||||
var hash = {goodbyes: new Clazz(), world: 'world'};
|
||||
|
||||
// Object property iteration order is undefined according to ECMA spec,
|
||||
// so we need to check both possible orders
|
||||
// @see http://stackoverflow.com/questions/280713/elements-order-in-a-for-in-loop
|
||||
var actual = compileWithPartials(string, hash);
|
||||
var expected1 = "<b>#1</b>. goodbye! 2. GOODBYE! cruel world!";
|
||||
var expected2 = "2. GOODBYE! <b>#1</b>. goodbye! cruel world!";
|
||||
var expected1 = '<b>#1</b>. goodbye! 2. GOODBYE! cruel world!';
|
||||
var expected2 = '2. GOODBYE! <b>#1</b>. goodbye! cruel world!';
|
||||
|
||||
equals(actual === expected1 || actual === expected2, true, "each with object argument iterates over the contents when not empty");
|
||||
equals(actual === expected1 || actual === expected2, true, 'each with object argument iterates over the contents when not empty');
|
||||
shouldCompileTo(string, {goodbyes: {}, world: 'world'}, 'cruel world!');
|
||||
});
|
||||
|
||||
it("each with @index", function() {
|
||||
var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!";
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
it('each with @index', function() {
|
||||
var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
equal(result, "0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!", "The @index variable is used");
|
||||
equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used');
|
||||
});
|
||||
|
||||
it("each with nested @index", function() {
|
||||
var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}cruel {{world}}!";
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
it('each with nested @index', function() {
|
||||
var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
equal(result, "0. goodbye! 0 1 2 After 0 1. Goodbye! 0 1 2 After 1 2. GOODBYE! 0 1 2 After 2 cruel world!", "The @index variable is used");
|
||||
equal(result, '0. goodbye! 0 1 2 After 0 1. Goodbye! 0 1 2 After 1 2. GOODBYE! 0 1 2 After 2 cruel world!', 'The @index variable is used');
|
||||
});
|
||||
|
||||
it('each with block params', function() {
|
||||
var string = '{{#each goodbyes as |value index|}}{{index}}. {{value.text}}! {{#each ../goodbyes as |childValue childIndex|}} {{index}} {{childIndex}}{{/each}} After {{index}} {{/each}}{{index}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}], world: 'world'};
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}], world: 'world'};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
@@ -131,88 +130,88 @@ describe('builtin helpers', function() {
|
||||
equal(result, '0. goodbye! 0 0 0 1 After 0 1. Goodbye! 1 0 1 1 After 1 cruel world!');
|
||||
});
|
||||
|
||||
it("each object with @index", function() {
|
||||
var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!";
|
||||
var hash = {goodbyes: {'a': {text: "goodbye"}, b: {text: "Goodbye"}, c: {text: "GOODBYE"}}, world: "world"};
|
||||
it('each object with @index', function() {
|
||||
var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: {'a': {text: 'goodbye'}, b: {text: 'Goodbye'}, c: {text: 'GOODBYE'}}, world: 'world'};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
equal(result, "0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!", "The @index variable is used");
|
||||
equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used');
|
||||
});
|
||||
|
||||
|
||||
it("each with @first", function() {
|
||||
var string = "{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!";
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
it('each with @first', function() {
|
||||
var string = '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
equal(result, "goodbye! cruel world!", "The @first variable is used");
|
||||
equal(result, 'goodbye! cruel world!', 'The @first variable is used');
|
||||
});
|
||||
|
||||
it("each with nested @first", function() {
|
||||
var string = "{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!";
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
it('each with nested @first', function() {
|
||||
var string = '{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
equal(result, "(goodbye! goodbye! goodbye!) (goodbye!) (goodbye!) cruel world!", "The @first variable is used");
|
||||
equal(result, '(goodbye! goodbye! goodbye!) (goodbye!) (goodbye!) cruel world!', 'The @first variable is used');
|
||||
});
|
||||
|
||||
it("each object with @first", function() {
|
||||
var string = "{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!";
|
||||
var hash = {goodbyes: {'foo': {text: "goodbye"}, bar: {text: "Goodbye"}}, world: "world"};
|
||||
it('each object with @first', function() {
|
||||
var string = '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: {'foo': {text: 'goodbye'}, bar: {text: 'Goodbye'}}, world: 'world'};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
equal(result, "goodbye! cruel world!", "The @first variable is used");
|
||||
equal(result, 'goodbye! cruel world!', 'The @first variable is used');
|
||||
});
|
||||
|
||||
it("each with @last", function() {
|
||||
var string = "{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!";
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
it('each with @last', function() {
|
||||
var string = '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
equal(result, "GOODBYE! cruel world!", "The @last variable is used");
|
||||
equal(result, 'GOODBYE! cruel world!', 'The @last variable is used');
|
||||
});
|
||||
|
||||
it("each object with @last", function() {
|
||||
var string = "{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!";
|
||||
var hash = {goodbyes: {'foo': {text: "goodbye"}, bar: {text: "Goodbye"}}, world: "world"};
|
||||
it('each object with @last', function() {
|
||||
var string = '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: {'foo': {text: 'goodbye'}, bar: {text: 'Goodbye'}}, world: 'world'};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
equal(result, "Goodbye! cruel world!", "The @last variable is used");
|
||||
equal(result, 'Goodbye! cruel world!', 'The @last variable is used');
|
||||
});
|
||||
|
||||
it("each with nested @last", function() {
|
||||
var string = "{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!";
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
it('each with nested @last', function() {
|
||||
var string = '{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
equal(result, "(GOODBYE!) (GOODBYE!) (GOODBYE! GOODBYE! GOODBYE!) cruel world!", "The @last variable is used");
|
||||
equal(result, '(GOODBYE!) (GOODBYE!) (GOODBYE! GOODBYE! GOODBYE!) cruel world!', 'The @last variable is used');
|
||||
});
|
||||
|
||||
it("each with function argument", function() {
|
||||
var string = "{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!";
|
||||
var hash = {goodbyes: function () { return [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}];}, world: "world"};
|
||||
shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!",
|
||||
"each with array function argument iterates over the contents when not empty");
|
||||
shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
|
||||
"each with array function argument ignores the contents when empty");
|
||||
it('each with function argument', function() {
|
||||
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
||||
var hash = {goodbyes: function() { return [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]; }, world: 'world'};
|
||||
shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!',
|
||||
'each with array function argument iterates over the contents when not empty');
|
||||
shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
|
||||
'each with array function argument ignores the contents when empty');
|
||||
});
|
||||
|
||||
it("data passed to helpers", function() {
|
||||
var string = "{{#each letters}}{{this}}{{detectDataInsideEach}}{{/each}}";
|
||||
it('data passed to helpers', function() {
|
||||
var string = '{{#each letters}}{{this}}{{detectDataInsideEach}}{{/each}}';
|
||||
var hash = {letters: ['a', 'b', 'c']};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
@@ -224,106 +223,108 @@ describe('builtin helpers', function() {
|
||||
equal(result, 'a!b!c!', 'should output data');
|
||||
});
|
||||
|
||||
it("each on implicit context", function() {
|
||||
it('each on implicit context', function() {
|
||||
shouldThrow(function() {
|
||||
var template = CompilerContext.compile("{{#each}}{{text}}! {{/each}}cruel world!");
|
||||
var template = CompilerContext.compile('{{#each}}{{text}}! {{/each}}cruel world!');
|
||||
template({});
|
||||
}, handlebarsEnv.Exception, 'Must pass iterator to #each');
|
||||
});
|
||||
});
|
||||
|
||||
describe("#log", function() {
|
||||
describe('#log', function() {
|
||||
/*eslint-disable no-console */
|
||||
if (typeof console === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
var log,
|
||||
info,
|
||||
error;
|
||||
var $log,
|
||||
$info,
|
||||
$error;
|
||||
beforeEach(function() {
|
||||
log = console.log;
|
||||
info = console.info;
|
||||
error = console.error;
|
||||
$log = console.log;
|
||||
$info = console.info;
|
||||
$error = console.error;
|
||||
});
|
||||
afterEach(function() {
|
||||
console.log = log;
|
||||
console.info = info;
|
||||
console.error = error;
|
||||
console.log = $log;
|
||||
console.info = $info;
|
||||
console.error = $error;
|
||||
});
|
||||
|
||||
it('should call logger at default level', function() {
|
||||
var string = "{{log blah}}";
|
||||
var hash = { blah: "whee" };
|
||||
var string = '{{log blah}}';
|
||||
var hash = { blah: 'whee' };
|
||||
|
||||
var levelArg, logArg;
|
||||
handlebarsEnv.log = function(level, 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");
|
||||
equals("whee", logArg, "should call log with 'whee'");
|
||||
shouldCompileTo(string, hash, '', 'log should not display');
|
||||
equals(1, levelArg, 'should call log with 1');
|
||||
equals('whee', logArg, "should call log with 'whee'");
|
||||
});
|
||||
it('should call logger at data level', function() {
|
||||
var string = "{{log blah}}";
|
||||
var hash = { blah: "whee" };
|
||||
var string = '{{log blah}}';
|
||||
var hash = { blah: 'whee' };
|
||||
|
||||
var levelArg, logArg;
|
||||
handlebarsEnv.log = function(level, arg){
|
||||
handlebarsEnv.log = function(level, arg) {
|
||||
levelArg = level;
|
||||
logArg = arg;
|
||||
};
|
||||
|
||||
shouldCompileTo(string, [hash,,,,{level: '03'}], "");
|
||||
shouldCompileTo(string, [hash,,,, {level: '03'}], '');
|
||||
equals(3, levelArg);
|
||||
equals("whee", logArg);
|
||||
equals('whee', logArg);
|
||||
});
|
||||
it('should output to info', function() {
|
||||
var string = "{{log blah}}";
|
||||
var hash = { blah: "whee" };
|
||||
var string = '{{log blah}}';
|
||||
var hash = { blah: 'whee' };
|
||||
var called;
|
||||
|
||||
console.info = function(log) {
|
||||
equals("whee", log);
|
||||
console.info = function(info) {
|
||||
equals('whee', info);
|
||||
called = true;
|
||||
};
|
||||
console.log = function(log) {
|
||||
equals("whee", log);
|
||||
equals('whee', log);
|
||||
called = true;
|
||||
};
|
||||
|
||||
shouldCompileTo(string, hash, "");
|
||||
shouldCompileTo(string, hash, '');
|
||||
equals(true, called);
|
||||
});
|
||||
it('should log at data level', function() {
|
||||
var string = "{{log blah}}";
|
||||
var hash = { blah: "whee" };
|
||||
var string = '{{log blah}}';
|
||||
var hash = { blah: 'whee' };
|
||||
var called;
|
||||
|
||||
console.error = function(log) {
|
||||
equals("whee", log);
|
||||
equals('whee', log);
|
||||
called = true;
|
||||
};
|
||||
|
||||
shouldCompileTo(string, [hash,,,,{level: '03'}], "");
|
||||
shouldCompileTo(string, [hash,,,, {level: '03'}], '');
|
||||
equals(true, called);
|
||||
});
|
||||
it('should handle missing logger', function() {
|
||||
var string = "{{log blah}}";
|
||||
var hash = { blah: "whee" };
|
||||
var string = '{{log blah}}';
|
||||
var hash = { blah: 'whee' };
|
||||
|
||||
console.error = undefined;
|
||||
|
||||
shouldCompileTo(string, [hash,,,,{level: '03'}], "");
|
||||
shouldCompileTo(string, [hash,,,, {level: '03'}], '');
|
||||
});
|
||||
/*eslint-enable no-console */
|
||||
});
|
||||
|
||||
|
||||
describe('#lookup', function() {
|
||||
it('should lookup arbitrary content', function() {
|
||||
var string = '{{#each goodbyes}}{{lookup ../data .}}{{/each}}',
|
||||
hash = {goodbyes: [0, 1], data: ['foo', 'bar']};
|
||||
hash = {goodbyes: [0, 1], data: ['foo', 'bar']};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
@@ -332,7 +333,7 @@ describe('builtin helpers', function() {
|
||||
});
|
||||
it('should not fail on undefined value', function() {
|
||||
var string = '{{#each goodbyes}}{{lookup ../bar .}}{{/each}}',
|
||||
hash = {goodbyes: [0, 1], data: ['foo', 'bar']};
|
||||
hash = {goodbyes: [0, 1], data: ['foo', 'bar']};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
+4
-6
@@ -1,5 +1,3 @@
|
||||
/*global Handlebars, shouldThrow */
|
||||
|
||||
describe('compiler', function() {
|
||||
if (!Handlebars.compile) {
|
||||
return;
|
||||
@@ -41,10 +39,10 @@ describe('compiler', function() {
|
||||
});
|
||||
|
||||
it('can utilize AST instance', function() {
|
||||
equal(Handlebars.compile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement("Hello")], null, {}))(), 'Hello');
|
||||
equal(Handlebars.compile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement('Hello')], null, {}))(), 'Hello');
|
||||
});
|
||||
|
||||
it("can pass through an empty string", function() {
|
||||
it('can pass through an empty string', function() {
|
||||
equal(Handlebars.compile('')(), '');
|
||||
});
|
||||
});
|
||||
@@ -60,10 +58,10 @@ describe('compiler', function() {
|
||||
});
|
||||
|
||||
it('can utilize AST instance', function() {
|
||||
equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement("Hello")]), null, {})), true);
|
||||
equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement('Hello')]), null, {})), true);
|
||||
});
|
||||
|
||||
it("can pass through an empty string", function() {
|
||||
it('can pass through an empty string', function() {
|
||||
equal(/return ""/.test(Handlebars.precompile('')), true);
|
||||
});
|
||||
});
|
||||
|
||||
+83
-80
@@ -1,25 +1,24 @@
|
||||
/*global CompilerContext, Handlebars, handlebarsEnv, shouldThrow */
|
||||
describe('data', function() {
|
||||
it("passing in data to a compiled function that expects data - works with helpers", function() {
|
||||
var template = CompilerContext.compile("{{hello}}", {data: true});
|
||||
it('passing in data to a compiled function that expects data - works with helpers', function() {
|
||||
var template = CompilerContext.compile('{{hello}}', {data: true});
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
return options.data.adjective + " " + this.noun;
|
||||
return options.data.adjective + ' ' + this.noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({noun: "cat"}, {helpers: helpers, data: {adjective: "happy"}});
|
||||
equals("happy cat", result, "Data output by helper");
|
||||
var result = template({noun: 'cat'}, {helpers: helpers, data: {adjective: 'happy'}});
|
||||
equals('happy cat', result, 'Data output by helper');
|
||||
});
|
||||
|
||||
it("data can be looked up via @foo", function() {
|
||||
var template = CompilerContext.compile("{{@hello}}");
|
||||
var result = template({}, { data: { hello: "hello" } });
|
||||
equals("hello", result, "@foo retrieves template data");
|
||||
it('data can be looked up via @foo', function() {
|
||||
var template = CompilerContext.compile('{{@hello}}');
|
||||
var result = template({}, { data: { hello: 'hello' } });
|
||||
equals('hello', result, '@foo retrieves template data');
|
||||
});
|
||||
|
||||
it("deep @foo triggers automatic top-level data", function() {
|
||||
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 = Handlebars.createFrame(handlebarsEnv.helpers);
|
||||
@@ -28,65 +27,67 @@ describe('data', function() {
|
||||
var frame = Handlebars.createFrame(options.data);
|
||||
|
||||
for (var prop in options.hash) {
|
||||
frame[prop] = options.hash[prop];
|
||||
if (prop in options.hash) {
|
||||
frame[prop] = options.hash[prop];
|
||||
}
|
||||
}
|
||||
return options.fn(this, { data: frame });
|
||||
};
|
||||
|
||||
var result = template({ foo: true }, { helpers: helpers });
|
||||
equals("Hello world", result, "Automatic data was triggered");
|
||||
equals('Hello world', result, 'Automatic data was triggered');
|
||||
});
|
||||
|
||||
it("parameter data can be looked up via @foo", function() {
|
||||
var template = CompilerContext.compile("{{hello @world}}");
|
||||
it('parameter data can be looked up via @foo', function() {
|
||||
var template = CompilerContext.compile('{{hello @world}}');
|
||||
var helpers = {
|
||||
hello: function(noun) {
|
||||
return "Hello " + noun;
|
||||
return 'Hello ' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers, data: { world: "world" } });
|
||||
equals("Hello world", result, "@foo as a parameter retrieves template data");
|
||||
var result = template({}, { helpers: helpers, data: { world: 'world' } });
|
||||
equals('Hello world', result, '@foo as a parameter retrieves template data');
|
||||
});
|
||||
|
||||
it("hash values can be looked up via @foo", function() {
|
||||
var template = CompilerContext.compile("{{hello noun=@world}}");
|
||||
it('hash values can be looked up via @foo', function() {
|
||||
var template = CompilerContext.compile('{{hello noun=@world}}');
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
return "Hello " + options.hash.noun;
|
||||
return 'Hello ' + options.hash.noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers, data: { world: "world" } });
|
||||
equals("Hello world", result, "@foo as a parameter retrieves template data");
|
||||
var result = template({}, { helpers: helpers, data: { world: 'world' } });
|
||||
equals('Hello world', result, '@foo as a parameter retrieves template data');
|
||||
});
|
||||
|
||||
it("nested parameter data can be looked up via @foo.bar", function() {
|
||||
var template = CompilerContext.compile("{{hello @world.bar}}");
|
||||
it('nested parameter data can be looked up via @foo.bar', function() {
|
||||
var template = CompilerContext.compile('{{hello @world.bar}}');
|
||||
var helpers = {
|
||||
hello: function(noun) {
|
||||
return "Hello " + noun;
|
||||
return 'Hello ' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers, data: { world: {bar: "world" } } });
|
||||
equals("Hello world", result, "@foo as a parameter retrieves template data");
|
||||
var result = template({}, { helpers: helpers, data: { world: {bar: 'world' } } });
|
||||
equals('Hello world', result, '@foo as a parameter retrieves template data');
|
||||
});
|
||||
|
||||
it("nested parameter data does not fail with @world.bar", function() {
|
||||
var template = CompilerContext.compile("{{hello @world.bar}}");
|
||||
it('nested parameter data does not fail with @world.bar', function() {
|
||||
var template = CompilerContext.compile('{{hello @world.bar}}');
|
||||
var helpers = {
|
||||
hello: function(noun) {
|
||||
return "Hello " + noun;
|
||||
return 'Hello ' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers, data: { foo: {bar: "world" } } });
|
||||
equals("Hello undefined", result, "@foo as a parameter retrieves template data");
|
||||
var result = template({}, { helpers: helpers, data: { foo: {bar: 'world' } } });
|
||||
equals('Hello undefined', result, '@foo as a parameter retrieves template data');
|
||||
});
|
||||
|
||||
it("parameter data throws when using complex scope references", function() {
|
||||
var string = "{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}";
|
||||
it('parameter data throws when using complex scope references', function() {
|
||||
var string = '{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}';
|
||||
|
||||
shouldThrow(function() {
|
||||
CompilerContext.compile(string);
|
||||
@@ -104,131 +105,133 @@ describe('data', function() {
|
||||
equals('hello', result);
|
||||
});
|
||||
|
||||
it("data is inherited downstream", function() {
|
||||
var template = CompilerContext.compile("{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}", { data: true });
|
||||
it('data is inherited downstream', function() {
|
||||
var template = CompilerContext.compile('{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}', { data: true });
|
||||
var helpers = {
|
||||
let: function(options) {
|
||||
var frame = Handlebars.createFrame(options.data);
|
||||
for (var prop in options.hash) {
|
||||
frame[prop] = options.hash[prop];
|
||||
if (prop in options.hash) {
|
||||
frame[prop] = options.hash[prop];
|
||||
}
|
||||
}
|
||||
return options.fn(this, {data: frame});
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({ bar: { baz: "hello world" } }, { helpers: helpers, data: {} });
|
||||
equals("2hello world1", result, "data variables are inherited downstream");
|
||||
var result = template({ bar: { baz: 'hello world' } }, { helpers: helpers, data: {} });
|
||||
equals('2hello world1', result, 'data variables are inherited downstream');
|
||||
});
|
||||
|
||||
it("passing in data to a compiled function that expects data - works with helpers in partials", function() {
|
||||
var template = CompilerContext.compile("{{>my_partial}}", {data: true});
|
||||
it('passing in data to a compiled function that expects data - works with helpers in partials', function() {
|
||||
var template = CompilerContext.compile('{{>myPartial}}', {data: true});
|
||||
|
||||
var partials = {
|
||||
my_partial: CompilerContext.compile("{{hello}}", {data: true})
|
||||
myPartial: CompilerContext.compile('{{hello}}', {data: true})
|
||||
};
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
return options.data.adjective + " " + this.noun;
|
||||
return options.data.adjective + ' ' + this.noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({noun: "cat"}, {helpers: helpers, partials: partials, data: {adjective: "happy"}});
|
||||
equals("happy cat", result, "Data output by helper inside partial");
|
||||
var result = template({noun: 'cat'}, {helpers: helpers, partials: partials, data: {adjective: 'happy'}});
|
||||
equals('happy cat', result, 'Data output by helper inside partial');
|
||||
});
|
||||
|
||||
it("passing in data to a compiled function that expects data - works with helpers and parameters", function() {
|
||||
var template = CompilerContext.compile("{{hello world}}", {data: true});
|
||||
it('passing in data to a compiled function that expects data - works with helpers and parameters', function() {
|
||||
var template = CompilerContext.compile('{{hello world}}', {data: true});
|
||||
|
||||
var helpers = {
|
||||
hello: function(noun, options) {
|
||||
return options.data.adjective + " " + noun + (this.exclaim ? "!" : "");
|
||||
return options.data.adjective + ' ' + noun + (this.exclaim ? '!' : '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({exclaim: true, world: "world"}, {helpers: helpers, data: {adjective: "happy"}});
|
||||
equals("happy world!", result, "Data output by helper");
|
||||
var result = template({exclaim: true, world: 'world'}, {helpers: helpers, data: {adjective: 'happy'}});
|
||||
equals('happy world!', result, 'Data output by helper');
|
||||
});
|
||||
|
||||
it("passing in data to a compiled function that expects data - works with block helpers", function() {
|
||||
var template = CompilerContext.compile("{{#hello}}{{world}}{{/hello}}", {data: true});
|
||||
it('passing in data to a compiled function that expects data - works with block helpers', function() {
|
||||
var template = CompilerContext.compile('{{#hello}}{{world}}{{/hello}}', {data: true});
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
return options.fn(this);
|
||||
},
|
||||
world: function(options) {
|
||||
return options.data.adjective + " world" + (this.exclaim ? "!" : "");
|
||||
return options.data.adjective + ' world' + (this.exclaim ? '!' : '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({exclaim: true}, {helpers: helpers, data: {adjective: "happy"}});
|
||||
equals("happy world!", result, "Data output by helper");
|
||||
var result = template({exclaim: true}, {helpers: helpers, data: {adjective: 'happy'}});
|
||||
equals('happy world!', result, 'Data output by helper');
|
||||
});
|
||||
|
||||
it("passing in data to a compiled function that expects data - works with block helpers that use ..", function() {
|
||||
var template = CompilerContext.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true});
|
||||
it('passing in data to a compiled function that expects data - works with block helpers that use ..', function() {
|
||||
var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true});
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
return options.fn({exclaim: "?"});
|
||||
return options.fn({exclaim: '?'});
|
||||
},
|
||||
world: function(thing, options) {
|
||||
return options.data.adjective + " " + thing + (this.exclaim || "");
|
||||
return options.data.adjective + ' ' + thing + (this.exclaim || '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({exclaim: true, zomg: "world"}, {helpers: helpers, data: {adjective: "happy"}});
|
||||
equals("happy world?", result, "Data output by helper");
|
||||
var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy'}});
|
||||
equals('happy world?', result, 'Data output by helper');
|
||||
});
|
||||
|
||||
it("passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..", function() {
|
||||
var template = CompilerContext.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true});
|
||||
it('passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..', function() {
|
||||
var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true});
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
return options.data.accessData + " " + options.fn({exclaim: "?"});
|
||||
return options.data.accessData + ' ' + options.fn({exclaim: '?'});
|
||||
},
|
||||
world: function(thing, options) {
|
||||
return options.data.adjective + " " + thing + (this.exclaim || "");
|
||||
return options.data.adjective + ' ' + thing + (this.exclaim || '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({exclaim: true, zomg: "world"}, {helpers: helpers, data: {adjective: "happy", accessData: "#win"}});
|
||||
equals("#win happy world?", result, "Data output by helper");
|
||||
var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy', accessData: '#win'}});
|
||||
equals('#win happy world?', result, 'Data output by helper');
|
||||
});
|
||||
|
||||
it("you can override inherited data when invoking a helper", function() {
|
||||
var template = CompilerContext.compile("{{#hello}}{{world zomg}}{{/hello}}", {data: true});
|
||||
it('you can override inherited data when invoking a helper', function() {
|
||||
var template = CompilerContext.compile('{{#hello}}{{world zomg}}{{/hello}}', {data: true});
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
return options.fn({exclaim: "?", zomg: "world"}, { data: {adjective: "sad"} });
|
||||
return options.fn({exclaim: '?', zomg: 'world'}, { data: {adjective: 'sad'} });
|
||||
},
|
||||
world: function(thing, options) {
|
||||
return options.data.adjective + " " + thing + (this.exclaim || "");
|
||||
return options.data.adjective + ' ' + thing + (this.exclaim || '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({exclaim: true, zomg: "planet"}, {helpers: helpers, data: {adjective: "happy"}});
|
||||
equals("sad world?", result, "Overriden data output by helper");
|
||||
var result = template({exclaim: true, zomg: 'planet'}, {helpers: helpers, data: {adjective: 'happy'}});
|
||||
equals('sad world?', result, 'Overriden data output by helper');
|
||||
});
|
||||
|
||||
|
||||
it("you can override inherited data when invoking a helper with depth", function() {
|
||||
var template = CompilerContext.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true});
|
||||
it('you can override inherited data when invoking a helper with depth', function() {
|
||||
var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true});
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
return options.fn({exclaim: "?"}, { data: {adjective: "sad"} });
|
||||
return options.fn({exclaim: '?'}, { data: {adjective: 'sad'} });
|
||||
},
|
||||
world: function(thing, options) {
|
||||
return options.data.adjective + " " + thing + (this.exclaim || "");
|
||||
return options.data.adjective + ' ' + thing + (this.exclaim || '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({exclaim: true, zomg: "world"}, {helpers: helpers, data: {adjective: "happy"}});
|
||||
equals("sad world?", result, "Overriden data output by helper");
|
||||
var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy'}});
|
||||
equals('sad world?', result, 'Overriden data output by helper');
|
||||
});
|
||||
|
||||
describe('@root', function() {
|
||||
|
||||
Vendored
+3
-3
@@ -1,8 +1,6 @@
|
||||
/*global handlebarsEnv */
|
||||
require('./common');
|
||||
|
||||
var _ = require('underscore'),
|
||||
fs = require('fs'),
|
||||
var fs = require('fs'),
|
||||
vm = require('vm');
|
||||
|
||||
global.Handlebars = 'no-conflict';
|
||||
@@ -21,10 +19,12 @@ global.CompilerContext = {
|
||||
};
|
||||
|
||||
function safeEval(templateSpec) {
|
||||
/*eslint-disable no-eval, no-console */
|
||||
try {
|
||||
return eval('(' + templateSpec + ')');
|
||||
} catch (err) {
|
||||
console.error(templateSpec);
|
||||
throw err;
|
||||
}
|
||||
/*eslint-enable no-eval, no-console */
|
||||
}
|
||||
|
||||
Vendored
+2
-3
@@ -1,4 +1,3 @@
|
||||
/*global CompilerContext, compileWithPartials, shouldCompileToWithPartials */
|
||||
global.shouldCompileTo = function(string, hashOrArray, expected, message) {
|
||||
shouldCompileToWithPartials(string, hashOrArray, false, expected, message);
|
||||
};
|
||||
@@ -14,7 +13,7 @@ global.compileWithPartials = function(string, hashOrArray, partials) {
|
||||
var template,
|
||||
ary,
|
||||
options;
|
||||
if(Object.prototype.toString.call(hashOrArray) === "[object Array]") {
|
||||
if (Object.prototype.toString.call(hashOrArray) === '[object Array]') {
|
||||
ary = [];
|
||||
ary.push(hashOrArray[0]);
|
||||
ary.push({ helpers: hashOrArray[1], partials: hashOrArray[2] });
|
||||
@@ -34,7 +33,7 @@ global.compileWithPartials = function(string, hashOrArray, partials) {
|
||||
|
||||
global.equals = global.equal = function(a, b, msg) {
|
||||
if (a !== b) {
|
||||
throw new Error("'" + a + "' should === '" + b + "'" + (msg ? ": " + msg : ''));
|
||||
throw new Error("'" + a + "' should === '" + b + "'" + (msg ? ': ' + msg : ''));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Vendored
+2
-1
@@ -1,4 +1,3 @@
|
||||
/*global handlebarsEnv */
|
||||
require('./common');
|
||||
|
||||
global.Handlebars = require('../../lib');
|
||||
@@ -14,10 +13,12 @@ global.CompilerContext = {
|
||||
};
|
||||
|
||||
function safeEval(templateSpec) {
|
||||
/*eslint-disable no-eval, no-console */
|
||||
try {
|
||||
return eval('(' + templateSpec + ')');
|
||||
} catch (err) {
|
||||
console.error(templateSpec);
|
||||
throw err;
|
||||
}
|
||||
/*eslint-enable no-eval, no-console */
|
||||
}
|
||||
|
||||
Vendored
+4
-1
@@ -1,3 +1,4 @@
|
||||
/*eslint-disable no-console */
|
||||
var fs = require('fs'),
|
||||
Mocha = require('mocha'),
|
||||
path = require('path');
|
||||
@@ -6,7 +7,7 @@ var errors = 0,
|
||||
testDir = path.dirname(__dirname),
|
||||
grep = process.argv[2];
|
||||
|
||||
var files = [ testDir + "/basic.js" ];
|
||||
var files = [ testDir + '/basic.js' ];
|
||||
|
||||
var files = fs.readdirSync(testDir)
|
||||
.filter(function(name) { return (/.*\.js$/).test(name); })
|
||||
@@ -15,7 +16,9 @@ var files = fs.readdirSync(testDir)
|
||||
run('./node', function() {
|
||||
run('./browser', function() {
|
||||
run('./runtime', function() {
|
||||
/*eslint-disable no-process-exit */
|
||||
process.exit(errors);
|
||||
/*eslint-enable no-process-exit */
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Vendored
+8
-8
@@ -1,8 +1,6 @@
|
||||
/*global handlebarsEnv */
|
||||
require('./common');
|
||||
|
||||
var _ = require('underscore'),
|
||||
fs = require('fs'),
|
||||
var fs = require('fs'),
|
||||
vm = require('vm');
|
||||
|
||||
global.Handlebars = 'no-conflict';
|
||||
@@ -10,15 +8,15 @@ vm.runInThisContext(fs.readFileSync(__dirname + '/../../dist/handlebars.runtime.
|
||||
|
||||
var parse = require('../../dist/cjs/handlebars/compiler/base').parse;
|
||||
var compiler = require('../../dist/cjs/handlebars/compiler/compiler');
|
||||
var JavaScriptCompiler = require('../../dist/cjs/handlebars/compiler/javascript-compiler')['default'];
|
||||
var JavaScriptCompiler = require('../../dist/cjs/handlebars/compiler/javascript-compiler');
|
||||
|
||||
global.CompilerContext = {
|
||||
browser: true,
|
||||
|
||||
compile: function(template, options) {
|
||||
// Hack the compiler on to the environment for these specific tests
|
||||
handlebarsEnv.precompile = function(template, options) {
|
||||
return compiler.precompile(template, options, handlebarsEnv);
|
||||
handlebarsEnv.precompile = function(precompileTemplate, precompileOptions) {
|
||||
return compiler.precompile(precompileTemplate, precompileOptions, handlebarsEnv);
|
||||
};
|
||||
handlebarsEnv.parse = parse;
|
||||
handlebarsEnv.Compiler = compiler.Compiler;
|
||||
@@ -29,8 +27,8 @@ global.CompilerContext = {
|
||||
},
|
||||
compileWithPartial: function(template, options) {
|
||||
// Hack the compiler on to the environment for these specific tests
|
||||
handlebarsEnv.compile = function(template, options) {
|
||||
return compiler.compile(template, options, handlebarsEnv);
|
||||
handlebarsEnv.compile = function(compileTemplate, compileOptions) {
|
||||
return compiler.compile(compileTemplate, compileOptions, handlebarsEnv);
|
||||
};
|
||||
handlebarsEnv.parse = parse;
|
||||
handlebarsEnv.Compiler = compiler.Compiler;
|
||||
@@ -41,10 +39,12 @@ global.CompilerContext = {
|
||||
};
|
||||
|
||||
function safeEval(templateSpec) {
|
||||
/*eslint-disable no-eval, no-console */
|
||||
try {
|
||||
return eval('(' + templateSpec + ')');
|
||||
} catch (err) {
|
||||
console.error(templateSpec);
|
||||
throw err;
|
||||
}
|
||||
/*eslint-enable no-eval, no-console */
|
||||
}
|
||||
|
||||
+264
-267
@@ -1,165 +1,164 @@
|
||||
/*global CompilerContext, Handlebars, shouldCompileTo, shouldCompileToWithPartials, shouldThrow, handlebarsEnv */
|
||||
describe('helpers', function() {
|
||||
it("helper with complex lookup$", function() {
|
||||
var string = "{{#goodbyes}}{{{link ../prefix}}}{{/goodbyes}}";
|
||||
var hash = {prefix: "/root", goodbyes: [{text: "Goodbye", url: "goodbye"}]};
|
||||
it('helper with complex lookup$', function() {
|
||||
var string = '{{#goodbyes}}{{{link ../prefix}}}{{/goodbyes}}';
|
||||
var hash = {prefix: '/root', goodbyes: [{text: 'Goodbye', url: 'goodbye'}]};
|
||||
var helpers = {link: function(prefix) {
|
||||
return "<a href='" + prefix + "/" + this.url + "'>" + this.text + "</a>";
|
||||
return '<a href="' + prefix + '/' + this.url + '">' + this.text + '</a>';
|
||||
}};
|
||||
shouldCompileTo(string, [hash, helpers], "<a href='/root/goodbye'>Goodbye</a>");
|
||||
shouldCompileTo(string, [hash, helpers], '<a href="/root/goodbye">Goodbye</a>');
|
||||
});
|
||||
|
||||
it("helper for raw block gets raw content", function() {
|
||||
var string = "{{{{raw}}}} {{test}} {{{{/raw}}}}";
|
||||
var hash = { test: "hello" };
|
||||
it('helper for raw block gets raw content', function() {
|
||||
var string = '{{{{raw}}}} {{test}} {{{{/raw}}}}';
|
||||
var hash = { test: 'hello' };
|
||||
var helpers = { raw: function(options) {
|
||||
return options.fn();
|
||||
} };
|
||||
shouldCompileTo(string, [hash, helpers], " {{test}} ",
|
||||
"raw block helper gets raw content");
|
||||
shouldCompileTo(string, [hash, helpers], ' {{test}} ',
|
||||
'raw block helper gets raw content');
|
||||
});
|
||||
|
||||
it("helper for raw block gets parameters", function() {
|
||||
var string = "{{{{raw 1 2 3}}}} {{test}} {{{{/raw}}}}";
|
||||
var hash = { test: "hello" };
|
||||
|
||||
it('helper for raw block gets parameters', function() {
|
||||
var string = '{{{{raw 1 2 3}}}} {{test}} {{{{/raw}}}}';
|
||||
var hash = { test: 'hello' };
|
||||
var helpers = { raw: function(a, b, c, options) {
|
||||
return options.fn() + a + b + c;
|
||||
} };
|
||||
shouldCompileTo(string, [hash, helpers], " {{test}} 123",
|
||||
"raw block helper gets raw content");
|
||||
shouldCompileTo(string, [hash, helpers], ' {{test}} 123',
|
||||
'raw block helper gets raw content');
|
||||
});
|
||||
|
||||
it("helper block with complex lookup expression", function() {
|
||||
var string = "{{#goodbyes}}{{../name}}{{/goodbyes}}";
|
||||
var hash = {name: "Alan"};
|
||||
|
||||
it('helper block with complex lookup expression', function() {
|
||||
var string = '{{#goodbyes}}{{../name}}{{/goodbyes}}';
|
||||
var hash = {name: 'Alan'};
|
||||
var helpers = {goodbyes: function(options) {
|
||||
var out = "";
|
||||
var byes = ["Goodbye", "goodbye", "GOODBYE"];
|
||||
for (var i = 0,j = byes.length; i < j; i++) {
|
||||
out += byes[i] + " " + options.fn(this) + "! ";
|
||||
var out = '';
|
||||
var byes = ['Goodbye', 'goodbye', 'GOODBYE'];
|
||||
for (var i = 0, j = byes.length; i < j; i++) {
|
||||
out += byes[i] + ' ' + options.fn(this) + '! ';
|
||||
}
|
||||
return out;
|
||||
}};
|
||||
shouldCompileTo(string, [hash, helpers], "Goodbye Alan! goodbye Alan! GOODBYE Alan! ");
|
||||
shouldCompileTo(string, [hash, helpers], 'Goodbye Alan! goodbye Alan! GOODBYE Alan! ');
|
||||
});
|
||||
|
||||
it("helper with complex lookup and nested template", function() {
|
||||
var string = "{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}";
|
||||
var hash = {prefix: '/root', goodbyes: [{text: "Goodbye", url: "goodbye"}]};
|
||||
var helpers = {link: function (prefix, options) {
|
||||
return "<a href='" + prefix + "/" + this.url + "'>" + options.fn(this) + "</a>";
|
||||
it('helper with complex lookup and nested template', function() {
|
||||
var string = '{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}';
|
||||
var hash = {prefix: '/root', goodbyes: [{text: 'Goodbye', url: 'goodbye'}]};
|
||||
var helpers = {link: function(prefix, options) {
|
||||
return '<a href="' + prefix + '/' + this.url + '">' + options.fn(this) + '</a>';
|
||||
}};
|
||||
shouldCompileToWithPartials(string, [hash, helpers], false, "<a href='/root/goodbye'>Goodbye</a>");
|
||||
shouldCompileToWithPartials(string, [hash, helpers], false, '<a href="/root/goodbye">Goodbye</a>');
|
||||
});
|
||||
|
||||
it("helper with complex lookup and nested template in VM+Compiler", function() {
|
||||
var string = "{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}";
|
||||
var hash = {prefix: '/root', goodbyes: [{text: "Goodbye", url: "goodbye"}]};
|
||||
var helpers = {link: function (prefix, options) {
|
||||
return "<a href='" + prefix + "/" + this.url + "'>" + options.fn(this) + "</a>";
|
||||
it('helper with complex lookup and nested template in VM+Compiler', function() {
|
||||
var string = '{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}';
|
||||
var hash = {prefix: '/root', goodbyes: [{text: 'Goodbye', url: 'goodbye'}]};
|
||||
var helpers = {link: function(prefix, options) {
|
||||
return '<a href="' + prefix + '/' + this.url + '">' + options.fn(this) + '</a>';
|
||||
}};
|
||||
shouldCompileToWithPartials(string, [hash, helpers], true, "<a href='/root/goodbye'>Goodbye</a>");
|
||||
shouldCompileToWithPartials(string, [hash, helpers], true, '<a href="/root/goodbye">Goodbye</a>');
|
||||
});
|
||||
it('helper returning undefined value', function() {
|
||||
shouldCompileTo(' {{nothere}}', [{}, {nothere: function() {}}], ' ');
|
||||
shouldCompileTo(' {{#nothere}}{{/nothere}}', [{}, {nothere: function() {}}], ' ');
|
||||
});
|
||||
|
||||
it("block helper", function() {
|
||||
var string = "{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!";
|
||||
it('block helper', function() {
|
||||
var string = '{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!';
|
||||
var template = CompilerContext.compile(string);
|
||||
|
||||
var result = template({world: "world"}, { helpers: {goodbyes: function(options) { return options.fn({text: "GOODBYE"}); }}});
|
||||
equal(result, "GOODBYE! cruel world!", "Block helper executed");
|
||||
var result = template({world: 'world'}, { helpers: {goodbyes: function(options) { return options.fn({text: 'GOODBYE'}); }}});
|
||||
equal(result, 'GOODBYE! cruel world!', 'Block helper executed');
|
||||
});
|
||||
|
||||
it("block helper staying in the same context", function() {
|
||||
var string = "{{#form}}<p>{{name}}</p>{{/form}}";
|
||||
it('block helper staying in the same context', function() {
|
||||
var string = '{{#form}}<p>{{name}}</p>{{/form}}';
|
||||
var template = CompilerContext.compile(string);
|
||||
|
||||
var result = template({name: "Yehuda"}, {helpers: {form: function(options) { return "<form>" + options.fn(this) + "</form>"; } }});
|
||||
equal(result, "<form><p>Yehuda</p></form>", "Block helper executed with current context");
|
||||
var result = template({name: 'Yehuda'}, {helpers: {form: function(options) { return '<form>' + options.fn(this) + '</form>'; } }});
|
||||
equal(result, '<form><p>Yehuda</p></form>', 'Block helper executed with current context');
|
||||
});
|
||||
|
||||
it("block helper should have context in this", function() {
|
||||
var source = "<ul>{{#people}}<li>{{#link}}{{name}}{{/link}}</li>{{/people}}</ul>";
|
||||
var link = function(options) {
|
||||
it('block helper should have context in this', function() {
|
||||
var source = '<ul>{{#people}}<li>{{#link}}{{name}}{{/link}}</li>{{/people}}</ul>';
|
||||
function link(options) {
|
||||
return '<a href="/people/' + this.id + '">' + options.fn(this) + '</a>';
|
||||
};
|
||||
var data = { "people": [
|
||||
{ "name": "Alan", "id": 1 },
|
||||
{ "name": "Yehuda", "id": 2 }
|
||||
}
|
||||
var data = { 'people': [
|
||||
{ 'name': 'Alan', 'id': 1 },
|
||||
{ 'name': 'Yehuda', 'id': 2 }
|
||||
]};
|
||||
|
||||
shouldCompileTo(source, [data, {link: link}], "<ul><li><a href=\"/people/1\">Alan</a></li><li><a href=\"/people/2\">Yehuda</a></li></ul>");
|
||||
shouldCompileTo(source, [data, {link: link}], '<ul><li><a href=\"/people/1\">Alan</a></li><li><a href=\"/people/2\">Yehuda</a></li></ul>');
|
||||
});
|
||||
|
||||
it("block helper for undefined value", function() {
|
||||
shouldCompileTo("{{#empty}}shouldn't render{{/empty}}", {}, "");
|
||||
it('block helper for undefined value', function() {
|
||||
shouldCompileTo("{{#empty}}shouldn't render{{/empty}}", {}, '');
|
||||
});
|
||||
|
||||
it("block helper passing a new context", function() {
|
||||
var string = "{{#form yehuda}}<p>{{name}}</p>{{/form}}";
|
||||
it('block helper passing a new context', function() {
|
||||
var string = '{{#form yehuda}}<p>{{name}}</p>{{/form}}';
|
||||
var template = CompilerContext.compile(string);
|
||||
|
||||
var result = template({yehuda: {name: "Yehuda"}}, { helpers: {form: function(context, options) { return "<form>" + options.fn(context) + "</form>"; }}});
|
||||
equal(result, "<form><p>Yehuda</p></form>", "Context variable resolved");
|
||||
var result = template({yehuda: {name: 'Yehuda'}}, { helpers: {form: function(context, options) { return '<form>' + options.fn(context) + '</form>'; }}});
|
||||
equal(result, '<form><p>Yehuda</p></form>', 'Context variable resolved');
|
||||
});
|
||||
|
||||
it("block helper passing a complex path context", function() {
|
||||
var string = "{{#form yehuda/cat}}<p>{{name}}</p>{{/form}}";
|
||||
it('block helper passing a complex path context', function() {
|
||||
var string = '{{#form yehuda/cat}}<p>{{name}}</p>{{/form}}';
|
||||
var template = CompilerContext.compile(string);
|
||||
|
||||
var result = template({yehuda: {name: "Yehuda", cat: {name: "Harold"}}}, { helpers: {form: function(context, options) { return "<form>" + options.fn(context) + "</form>"; }}});
|
||||
equal(result, "<form><p>Harold</p></form>", "Complex path variable resolved");
|
||||
var result = template({yehuda: {name: 'Yehuda', cat: {name: 'Harold'}}}, { helpers: {form: function(context, options) { return '<form>' + options.fn(context) + '</form>'; }}});
|
||||
equal(result, '<form><p>Harold</p></form>', 'Complex path variable resolved');
|
||||
});
|
||||
|
||||
it("nested block helpers", function() {
|
||||
var string = "{{#form yehuda}}<p>{{name}}</p>{{#link}}Hello{{/link}}{{/form}}";
|
||||
it('nested block helpers', function() {
|
||||
var string = '{{#form yehuda}}<p>{{name}}</p>{{#link}}Hello{{/link}}{{/form}}';
|
||||
var template = CompilerContext.compile(string);
|
||||
|
||||
var result = template({
|
||||
yehuda: {name: "Yehuda" }
|
||||
yehuda: {name: 'Yehuda' }
|
||||
}, {
|
||||
helpers: {
|
||||
link: function(options) { return "<a href='" + this.name + "'>" + options.fn(this) + "</a>"; },
|
||||
form: function(context, options) { return "<form>" + options.fn(context) + "</form>"; }
|
||||
link: function(options) { return '<a href="' + this.name + '">' + options.fn(this) + '</a>'; },
|
||||
form: function(context, options) { return '<form>' + options.fn(context) + '</form>'; }
|
||||
}
|
||||
});
|
||||
equal(result, "<form><p>Yehuda</p><a href='Yehuda'>Hello</a></form>", "Both blocks executed");
|
||||
equal(result, '<form><p>Yehuda</p><a href="Yehuda">Hello</a></form>', 'Both blocks executed');
|
||||
});
|
||||
|
||||
it("block helper inverted sections", function() {
|
||||
var string = "{{#list people}}{{name}}{{^}}<em>Nobody's here</em>{{/list}}";
|
||||
var list = function(context, options) {
|
||||
it('block helper inverted sections', function() {
|
||||
var string = '{{#list people}}{{name}}{{^}}<em>Nobody\'s here</em>{{/list}}';
|
||||
function list(context, options) {
|
||||
if (context.length > 0) {
|
||||
var out = "<ul>";
|
||||
for(var i = 0,j=context.length; i < j; i++) {
|
||||
out += "<li>";
|
||||
var out = '<ul>';
|
||||
for (var i = 0, j = context.length; i < j; i++) {
|
||||
out += '<li>';
|
||||
out += options.fn(context[i]);
|
||||
out += "</li>";
|
||||
out += '</li>';
|
||||
}
|
||||
out += "</ul>";
|
||||
out += '</ul>';
|
||||
return out;
|
||||
} else {
|
||||
return "<p>" + options.inverse(this) + "</p>";
|
||||
return '<p>' + options.inverse(this) + '</p>';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var hash = {people: [{name: "Alan"}, {name: "Yehuda"}]};
|
||||
var hash = {people: [{name: 'Alan'}, {name: 'Yehuda'}]};
|
||||
var empty = {people: []};
|
||||
var rootMessage = {
|
||||
people: [],
|
||||
message: "Nobody's here"
|
||||
message: 'Nobody\'s here'
|
||||
};
|
||||
|
||||
var messageString = "{{#list people}}Hello{{^}}{{message}}{{/list}}";
|
||||
var messageString = '{{#list people}}Hello{{^}}{{message}}{{/list}}';
|
||||
|
||||
// the meaning here may be kind of hard to catch, but list.not is always called,
|
||||
// so we should see the output of both
|
||||
shouldCompileTo(string, [hash, { list: list }], "<ul><li>Alan</li><li>Yehuda</li></ul>", "an inverse wrapper is passed in as a new context");
|
||||
shouldCompileTo(string, [empty, { list: list }], "<p><em>Nobody's here</em></p>", "an inverse wrapper can be optionally called");
|
||||
shouldCompileTo(messageString, [rootMessage, { list: list }], "<p>Nobody's here</p>", "the context of an inverse is the parent of the block");
|
||||
shouldCompileTo(string, [hash, { list: list }], '<ul><li>Alan</li><li>Yehuda</li></ul>', 'an inverse wrapper is passed in as a new context');
|
||||
shouldCompileTo(string, [empty, { list: list }], '<p><em>Nobody\'s here</em></p>', 'an inverse wrapper can be optionally called');
|
||||
shouldCompileTo(messageString, [rootMessage, { list: list }], '<p>Nobody's here</p>', 'the context of an inverse is the parent of the block');
|
||||
});
|
||||
|
||||
it('pathed lambas with parameters', function() {
|
||||
@@ -178,43 +177,47 @@ describe('helpers', function() {
|
||||
shouldCompileTo('{{hash/helper 1}}', [hash, helpers], 'winning');
|
||||
});
|
||||
|
||||
describe("helpers hash", function() {
|
||||
it("providing a helpers hash", function() {
|
||||
shouldCompileTo("Goodbye {{cruel}} {{world}}!", [{cruel: "cruel"}, {world: function() { return "world"; }}], "Goodbye cruel world!",
|
||||
"helpers hash is available");
|
||||
describe('helpers hash', function() {
|
||||
it('providing a helpers hash', function() {
|
||||
shouldCompileTo('Goodbye {{cruel}} {{world}}!', [{cruel: 'cruel'}, {world: function() { return 'world'; }}], 'Goodbye cruel world!',
|
||||
'helpers hash is available');
|
||||
|
||||
shouldCompileTo("Goodbye {{#iter}}{{cruel}} {{world}}{{/iter}}!", [{iter: [{cruel: "cruel"}]}, {world: function() { return "world"; }}],
|
||||
"Goodbye cruel world!", "helpers hash is available inside other blocks");
|
||||
shouldCompileTo('Goodbye {{#iter}}{{cruel}} {{world}}{{/iter}}!', [{iter: [{cruel: 'cruel'}]}, {world: function() { return 'world'; }}],
|
||||
'Goodbye cruel world!', 'helpers hash is available inside other blocks');
|
||||
});
|
||||
|
||||
it("in cases of conflict, helpers win", function() {
|
||||
shouldCompileTo("{{{lookup}}}", [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], "helpers",
|
||||
"helpers hash has precedence escaped expansion");
|
||||
shouldCompileTo("{{lookup}}", [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], "helpers",
|
||||
"helpers hash has precedence simple expansion");
|
||||
it('in cases of conflict, helpers win', function() {
|
||||
shouldCompileTo('{{{lookup}}}', [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], 'helpers',
|
||||
'helpers hash has precedence escaped expansion');
|
||||
shouldCompileTo('{{lookup}}', [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], 'helpers',
|
||||
'helpers hash has precedence simple expansion');
|
||||
});
|
||||
|
||||
it("the helpers hash is available is nested contexts", function() {
|
||||
shouldCompileTo("{{#outer}}{{#inner}}{{helper}}{{/inner}}{{/outer}}",
|
||||
[{'outer': {'inner': {'unused':[]}}}, {'helper': function() { return 'helper'; }}], "helper",
|
||||
"helpers hash is available in nested contexts.");
|
||||
it('the helpers hash is available is nested contexts', function() {
|
||||
shouldCompileTo(
|
||||
'{{#outer}}{{#inner}}{{helper}}{{/inner}}{{/outer}}',
|
||||
[
|
||||
{'outer': {'inner': {'unused': []}}},
|
||||
{'helper': function() { return 'helper'; }}
|
||||
],
|
||||
'helper',
|
||||
'helpers hash is available in nested contexts.');
|
||||
});
|
||||
|
||||
it("the helper hash should augment the global hash", function() {
|
||||
it('the helper hash should augment the global hash', function() {
|
||||
handlebarsEnv.registerHelper('test_helper', function() { return 'found it!'; });
|
||||
|
||||
shouldCompileTo(
|
||||
"{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}", [
|
||||
{cruel: "cruel"},
|
||||
{world: function() { return "world!"; }}
|
||||
'{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}', [
|
||||
{cruel: 'cruel'},
|
||||
{world: function() { return 'world!'; }}
|
||||
],
|
||||
"found it! Goodbye cruel world!!");
|
||||
'found it! Goodbye cruel world!!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('registration', function() {
|
||||
it('unregisters', function() {
|
||||
var helpers = handlebarsEnv.helpers;
|
||||
handlebarsEnv.helpers = {};
|
||||
|
||||
handlebarsEnv.registerHelper('foo', function() {
|
||||
@@ -230,134 +233,128 @@ describe('helpers', function() {
|
||||
|
||||
handlebarsEnv.registerHelper({
|
||||
'if': helpers['if'],
|
||||
world: function() { return "world!"; },
|
||||
test_helper: function() { return 'found it!'; }
|
||||
world: function() { return 'world!'; },
|
||||
testHelper: function() { return 'found it!'; }
|
||||
});
|
||||
|
||||
shouldCompileTo(
|
||||
"{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}",
|
||||
[{cruel: "cruel"}],
|
||||
"found it! Goodbye cruel world!!");
|
||||
'{{testHelper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}',
|
||||
[{cruel: 'cruel'}],
|
||||
'found it! Goodbye cruel world!!');
|
||||
});
|
||||
it('fails with multiple and args', function() {
|
||||
shouldThrow(function() {
|
||||
handlebarsEnv.registerHelper({
|
||||
world: function() { return "world!"; },
|
||||
test_helper: function() { return 'found it!'; }
|
||||
world: function() { return 'world!'; },
|
||||
testHelper: function() { return 'found it!'; }
|
||||
}, {});
|
||||
}, Error, 'Arg not supported with multiple helpers');
|
||||
});
|
||||
});
|
||||
|
||||
it("decimal number literals work", function() {
|
||||
var string = 'Message: {{hello -1.2 1.2}}';
|
||||
var hash = {};
|
||||
var helpers = {hello: function(times, times2) {
|
||||
if(typeof times !== 'number') { times = "NaN"; }
|
||||
if(typeof times2 !== 'number') { times2 = "NaN"; }
|
||||
return "Hello " + times + " " + times2 + " times";
|
||||
it('decimal number literals work', function() {
|
||||
var string = 'Message: {{hello -1.2 1.2}}';
|
||||
var helpers = {hello: function(times, times2) {
|
||||
if (typeof times !== 'number') { times = 'NaN'; }
|
||||
if (typeof times2 !== 'number') { times2 = 'NaN'; }
|
||||
return 'Hello ' + times + ' ' + times2 + ' times';
|
||||
}};
|
||||
shouldCompileTo(string, [hash, helpers], "Message: Hello -1.2 1.2 times", "template with a negative integer literal");
|
||||
shouldCompileTo(string, [{}, helpers], 'Message: Hello -1.2 1.2 times', 'template with a negative integer literal');
|
||||
});
|
||||
|
||||
it("negative number literals work", function() {
|
||||
var string = 'Message: {{hello -12}}';
|
||||
var hash = {};
|
||||
var helpers = {hello: function(times) {
|
||||
if(typeof times !== 'number') { times = "NaN"; }
|
||||
return "Hello " + times + " times";
|
||||
it('negative number literals work', function() {
|
||||
var string = 'Message: {{hello -12}}';
|
||||
var helpers = {hello: function(times) {
|
||||
if (typeof times !== 'number') { times = 'NaN'; }
|
||||
return 'Hello ' + times + ' times';
|
||||
}};
|
||||
shouldCompileTo(string, [hash, helpers], "Message: Hello -12 times", "template with a negative integer literal");
|
||||
shouldCompileTo(string, [{}, helpers], 'Message: Hello -12 times', 'template with a negative integer literal');
|
||||
});
|
||||
|
||||
describe("String literal parameters", function() {
|
||||
it("simple literals work", function() {
|
||||
var string = 'Message: {{hello "world" 12 true false}}';
|
||||
var hash = {};
|
||||
var helpers = {hello: function(param, times, bool1, bool2) {
|
||||
if(typeof times !== 'number') { times = "NaN"; }
|
||||
if(typeof bool1 !== 'boolean') { bool1 = "NaB"; }
|
||||
if(typeof bool2 !== 'boolean') { bool2 = "NaB"; }
|
||||
return "Hello " + param + " " + times + " times: " + bool1 + " " + bool2;
|
||||
describe('String literal parameters', function() {
|
||||
it('simple literals work', function() {
|
||||
var string = 'Message: {{hello "world" 12 true false}}';
|
||||
var helpers = {hello: function(param, times, bool1, bool2) {
|
||||
if (typeof times !== 'number') { times = 'NaN'; }
|
||||
if (typeof bool1 !== 'boolean') { bool1 = 'NaB'; }
|
||||
if (typeof bool2 !== 'boolean') { bool2 = 'NaB'; }
|
||||
return 'Hello ' + param + ' ' + times + ' times: ' + bool1 + ' ' + bool2;
|
||||
}};
|
||||
shouldCompileTo(string, [hash, helpers], "Message: Hello world 12 times: true false", "template with a simple String literal");
|
||||
shouldCompileTo(string, [{}, helpers], 'Message: Hello world 12 times: true false', 'template with a simple String literal');
|
||||
});
|
||||
|
||||
it("using a quote in the middle of a parameter raises an error", function() {
|
||||
var string = 'Message: {{hello wo"rld"}}';
|
||||
it('using a quote in the middle of a parameter raises an error', function() {
|
||||
var string = 'Message: {{hello wo"rld"}}';
|
||||
shouldThrow(function() {
|
||||
CompilerContext.compile(string);
|
||||
}, Error);
|
||||
});
|
||||
|
||||
it("escaping a String is possible", function(){
|
||||
var string = 'Message: {{{hello "\\"world\\""}}}';
|
||||
var hash = {};
|
||||
var helpers = {hello: function(param) { return "Hello " + param; }};
|
||||
shouldCompileTo(string, [hash, helpers], "Message: Hello \"world\"", "template with an escaped String literal");
|
||||
it('escaping a String is possible', function() {
|
||||
var string = 'Message: {{{hello "\\"world\\""}}}';
|
||||
var helpers = {hello: function(param) { return 'Hello ' + param; }};
|
||||
shouldCompileTo(string, [{}, helpers], 'Message: Hello "world"', 'template with an escaped String literal');
|
||||
});
|
||||
|
||||
it("it works with ' marks", function() {
|
||||
var string = 'Message: {{{hello "Alan\'s world"}}}';
|
||||
var hash = {};
|
||||
var helpers = {hello: function(param) { return "Hello " + param; }};
|
||||
shouldCompileTo(string, [hash, helpers], "Message: Hello Alan's world", "template with a ' mark");
|
||||
var string = 'Message: {{{hello "Alan\'s world"}}}';
|
||||
var helpers = {hello: function(param) { return 'Hello ' + param; }};
|
||||
shouldCompileTo(string, [{}, helpers], "Message: Hello Alan's world", "template with a ' mark");
|
||||
});
|
||||
});
|
||||
|
||||
it("negative number literals work", function() {
|
||||
var string = 'Message: {{hello -12}}';
|
||||
var hash = {};
|
||||
var helpers = {hello: function(times) {
|
||||
if(typeof times !== 'number') { times = "NaN"; }
|
||||
return "Hello " + times + " times";
|
||||
it('negative number literals work', function() {
|
||||
var string = 'Message: {{hello -12}}';
|
||||
var helpers = {hello: function(times) {
|
||||
if (typeof times !== 'number') { times = 'NaN'; }
|
||||
return 'Hello ' + times + ' times';
|
||||
}};
|
||||
shouldCompileTo(string, [hash, helpers], "Message: Hello -12 times", "template with a negative integer literal");
|
||||
shouldCompileTo(string, [{}, helpers], 'Message: Hello -12 times', 'template with a negative integer literal');
|
||||
});
|
||||
|
||||
describe("multiple parameters", function() {
|
||||
it("simple multi-params work", function() {
|
||||
var string = 'Message: {{goodbye cruel world}}';
|
||||
var hash = {cruel: "cruel", world: "world"};
|
||||
var helpers = {goodbye: function(cruel, world) { return "Goodbye " + cruel + " " + world; }};
|
||||
shouldCompileTo(string, [hash, helpers], "Message: Goodbye cruel world", "regular helpers with multiple params");
|
||||
describe('multiple parameters', function() {
|
||||
it('simple multi-params work', function() {
|
||||
var string = 'Message: {{goodbye cruel world}}';
|
||||
var hash = {cruel: 'cruel', world: 'world'};
|
||||
var helpers = {goodbye: function(cruel, world) { return 'Goodbye ' + cruel + ' ' + world; }};
|
||||
shouldCompileTo(string, [hash, helpers], 'Message: Goodbye cruel world', 'regular helpers with multiple params');
|
||||
});
|
||||
|
||||
it("block multi-params work", function() {
|
||||
var string = 'Message: {{#goodbye cruel world}}{{greeting}} {{adj}} {{noun}}{{/goodbye}}';
|
||||
var hash = {cruel: "cruel", world: "world"};
|
||||
it('block multi-params work', function() {
|
||||
var string = 'Message: {{#goodbye cruel world}}{{greeting}} {{adj}} {{noun}}{{/goodbye}}';
|
||||
var hash = {cruel: 'cruel', world: 'world'};
|
||||
var helpers = {goodbye: function(cruel, world, options) {
|
||||
return options.fn({greeting: "Goodbye", adj: cruel, noun: world});
|
||||
return options.fn({greeting: 'Goodbye', adj: cruel, noun: world});
|
||||
}};
|
||||
shouldCompileTo(string, [hash, helpers], "Message: Goodbye cruel world", "block helpers with multiple params");
|
||||
shouldCompileTo(string, [hash, helpers], 'Message: Goodbye cruel world', 'block helpers with multiple params');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hash', function() {
|
||||
it("helpers can take an optional hash", function() {
|
||||
it('helpers can take an optional hash', function() {
|
||||
var template = CompilerContext.compile('{{goodbye cruel="CRUEL" world="WORLD" times=12}}');
|
||||
|
||||
var helpers = {
|
||||
goodbye: function(options) {
|
||||
return "GOODBYE " + options.hash.cruel + " " + options.hash.world + " " + options.hash.times + " TIMES";
|
||||
return 'GOODBYE ' + options.hash.cruel + ' ' + options.hash.world + ' ' + options.hash.times + ' TIMES';
|
||||
}
|
||||
};
|
||||
|
||||
var context = {};
|
||||
|
||||
var result = template(context, {helpers: helpers});
|
||||
equals(result, "GOODBYE CRUEL WORLD 12 TIMES", "Helper output hash");
|
||||
equals(result, 'GOODBYE CRUEL WORLD 12 TIMES', 'Helper output hash');
|
||||
});
|
||||
|
||||
it("helpers can take an optional hash with booleans", function() {
|
||||
it('helpers can take an optional hash with booleans', function() {
|
||||
var helpers = {
|
||||
goodbye: function(options) {
|
||||
if (options.hash.print === true) {
|
||||
return "GOODBYE " + options.hash.cruel + " " + options.hash.world;
|
||||
return 'GOODBYE ' + options.hash.cruel + ' ' + options.hash.world;
|
||||
} else if (options.hash.print === false) {
|
||||
return "NOT PRINTING";
|
||||
return 'NOT PRINTING';
|
||||
} else {
|
||||
return "THIS SHOULD NOT HAPPEN";
|
||||
return 'THIS SHOULD NOT HAPPEN';
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -366,161 +363,161 @@ describe('helpers', function() {
|
||||
|
||||
var template = CompilerContext.compile('{{goodbye cruel="CRUEL" world="WORLD" print=true}}');
|
||||
var result = template(context, {helpers: helpers});
|
||||
equals(result, "GOODBYE CRUEL WORLD", "Helper output hash");
|
||||
equals(result, 'GOODBYE CRUEL WORLD', 'Helper output hash');
|
||||
|
||||
template = CompilerContext.compile('{{goodbye cruel="CRUEL" world="WORLD" print=false}}');
|
||||
result = template(context, {helpers: helpers});
|
||||
equals(result, "NOT PRINTING", "Boolean helper parameter honored");
|
||||
equals(result, 'NOT PRINTING', 'Boolean helper parameter honored');
|
||||
});
|
||||
|
||||
it("block helpers can take an optional hash", function() {
|
||||
it('block helpers can take an optional hash', function() {
|
||||
var template = CompilerContext.compile('{{#goodbye cruel="CRUEL" times=12}}world{{/goodbye}}');
|
||||
|
||||
var helpers = {
|
||||
goodbye: function(options) {
|
||||
return "GOODBYE " + options.hash.cruel + " " + options.fn(this) + " " + options.hash.times + " TIMES";
|
||||
return 'GOODBYE ' + options.hash.cruel + ' ' + options.fn(this) + ' ' + options.hash.times + ' TIMES';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, {helpers: helpers});
|
||||
equals(result, "GOODBYE CRUEL world 12 TIMES", "Hash parameters output");
|
||||
equals(result, 'GOODBYE CRUEL world 12 TIMES', 'Hash parameters output');
|
||||
});
|
||||
|
||||
it("block helpers can take an optional hash with single quoted stings", function() {
|
||||
var template = CompilerContext.compile("{{#goodbye cruel='CRUEL' times=12}}world{{/goodbye}}");
|
||||
it('block helpers can take an optional hash with single quoted stings', function() {
|
||||
var template = CompilerContext.compile('{{#goodbye cruel="CRUEL" times=12}}world{{/goodbye}}');
|
||||
|
||||
var helpers = {
|
||||
goodbye: function(options) {
|
||||
return "GOODBYE " + options.hash.cruel + " " + options.fn(this) + " " + options.hash.times + " TIMES";
|
||||
return 'GOODBYE ' + options.hash.cruel + ' ' + options.fn(this) + ' ' + options.hash.times + ' TIMES';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, {helpers: helpers});
|
||||
equals(result, "GOODBYE CRUEL world 12 TIMES", "Hash parameters output");
|
||||
equals(result, 'GOODBYE CRUEL world 12 TIMES', 'Hash parameters output');
|
||||
});
|
||||
|
||||
it("block helpers can take an optional hash with booleans", function() {
|
||||
it('block helpers can take an optional hash with booleans', function() {
|
||||
var helpers = {
|
||||
goodbye: function(options) {
|
||||
if (options.hash.print === true) {
|
||||
return "GOODBYE " + options.hash.cruel + " " + options.fn(this);
|
||||
return 'GOODBYE ' + options.hash.cruel + ' ' + options.fn(this);
|
||||
} else if (options.hash.print === false) {
|
||||
return "NOT PRINTING";
|
||||
return 'NOT PRINTING';
|
||||
} else {
|
||||
return "THIS SHOULD NOT HAPPEN";
|
||||
return 'THIS SHOULD NOT HAPPEN';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var template = CompilerContext.compile('{{#goodbye cruel="CRUEL" print=true}}world{{/goodbye}}');
|
||||
var result = template({}, {helpers: helpers});
|
||||
equals(result, "GOODBYE CRUEL world", "Boolean hash parameter honored");
|
||||
equals(result, 'GOODBYE CRUEL world', 'Boolean hash parameter honored');
|
||||
|
||||
template = CompilerContext.compile('{{#goodbye cruel="CRUEL" print=false}}world{{/goodbye}}');
|
||||
result = template({}, {helpers: helpers});
|
||||
equals(result, "NOT PRINTING", "Boolean hash parameter honored");
|
||||
equals(result, 'NOT PRINTING', 'Boolean hash parameter honored');
|
||||
});
|
||||
});
|
||||
|
||||
describe("helperMissing", function() {
|
||||
it("if a context is not found, helperMissing is used", function() {
|
||||
describe('helperMissing', function() {
|
||||
it('if a context is not found, helperMissing is used', function() {
|
||||
shouldThrow(function() {
|
||||
var template = CompilerContext.compile("{{hello}} {{link_to world}}");
|
||||
var template = CompilerContext.compile('{{hello}} {{link_to world}}');
|
||||
template({});
|
||||
}, undefined, /Missing helper: 'link_to'/);
|
||||
}, undefined, /Missing helper: "link_to"/);
|
||||
});
|
||||
|
||||
it("if a context is not found, custom helperMissing is used", function() {
|
||||
var string = "{{hello}} {{link_to world}}";
|
||||
var context = { hello: "Hello", world: "world" };
|
||||
it('if a context is not found, custom helperMissing is used', function() {
|
||||
var string = '{{hello}} {{link_to world}}';
|
||||
var context = { hello: 'Hello', world: 'world' };
|
||||
|
||||
var helpers = {
|
||||
helperMissing: function(mesg, options) {
|
||||
if(options.name === "link_to") {
|
||||
return new Handlebars.SafeString("<a>" + mesg + "</a>");
|
||||
if (options.name === 'link_to') {
|
||||
return new Handlebars.SafeString('<a>' + mesg + '</a>');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
shouldCompileTo(string, [context, helpers], "Hello <a>world</a>");
|
||||
shouldCompileTo(string, [context, helpers], 'Hello <a>world</a>');
|
||||
});
|
||||
|
||||
it("if a value is not found, custom helperMissing is used", function() {
|
||||
var string = "{{hello}} {{link_to}}";
|
||||
var context = { hello: "Hello", world: "world" };
|
||||
it('if a value is not found, custom helperMissing is used', function() {
|
||||
var string = '{{hello}} {{link_to}}';
|
||||
var context = { hello: 'Hello', world: 'world' };
|
||||
|
||||
var helpers = {
|
||||
helperMissing: function(options) {
|
||||
if(options.name === "link_to") {
|
||||
return new Handlebars.SafeString("<a>winning</a>");
|
||||
if (options.name === 'link_to') {
|
||||
return new Handlebars.SafeString('<a>winning</a>');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
shouldCompileTo(string, [context, helpers], "Hello <a>winning</a>");
|
||||
shouldCompileTo(string, [context, helpers], 'Hello <a>winning</a>');
|
||||
});
|
||||
});
|
||||
|
||||
describe("knownHelpers", function() {
|
||||
it("Known helper should render helper", function() {
|
||||
var template = CompilerContext.compile("{{hello}}", {knownHelpers: {"hello" : true}});
|
||||
describe('knownHelpers', function() {
|
||||
it('Known helper should render helper', function() {
|
||||
var template = CompilerContext.compile('{{hello}}', {knownHelpers: {hello: true}});
|
||||
|
||||
var result = template({}, {helpers: {hello: function() { return "foo"; }}});
|
||||
equal(result, "foo", "'foo' should === '" + result);
|
||||
var result = template({}, {helpers: {hello: function() { return 'foo'; }}});
|
||||
equal(result, 'foo', "'foo' should === '" + result);
|
||||
});
|
||||
|
||||
it("Unknown helper in knownHelpers only mode should be passed as undefined", function() {
|
||||
var template = CompilerContext.compile("{{typeof hello}}", {knownHelpers: {'typeof': true}, knownHelpersOnly: true});
|
||||
it('Unknown helper in knownHelpers only mode should be passed as undefined', function() {
|
||||
var template = CompilerContext.compile('{{typeof hello}}', {knownHelpers: {'typeof': true}, knownHelpersOnly: true});
|
||||
|
||||
var result = template({}, {helpers: {'typeof': function(arg) { return typeof arg; }, hello: function() { return "foo"; }}});
|
||||
equal(result, "undefined", "'undefined' should === '" + result);
|
||||
var result = template({}, {helpers: {'typeof': function(arg) { return typeof arg; }, hello: function() { return 'foo'; }}});
|
||||
equal(result, 'undefined', "'undefined' should === '" + result);
|
||||
});
|
||||
it("Builtin helpers available in knownHelpers only mode", function() {
|
||||
var template = CompilerContext.compile("{{#unless foo}}bar{{/unless}}", {knownHelpersOnly: true});
|
||||
it('Builtin helpers available in knownHelpers only mode', function() {
|
||||
var template = CompilerContext.compile('{{#unless foo}}bar{{/unless}}', {knownHelpersOnly: true});
|
||||
|
||||
var result = template({});
|
||||
equal(result, "bar", "'bar' should === '" + result);
|
||||
equal(result, 'bar', "'bar' should === '" + result);
|
||||
});
|
||||
it("Field lookup works in knownHelpers only mode", function() {
|
||||
var template = CompilerContext.compile("{{foo}}", {knownHelpersOnly: true});
|
||||
it('Field lookup works in knownHelpers only mode', function() {
|
||||
var template = CompilerContext.compile('{{foo}}', {knownHelpersOnly: true});
|
||||
|
||||
var result = template({foo: 'bar'});
|
||||
equal(result, "bar", "'bar' should === '" + result);
|
||||
equal(result, 'bar', "'bar' should === '" + result);
|
||||
});
|
||||
it("Conditional blocks work in knownHelpers only mode", function() {
|
||||
var template = CompilerContext.compile("{{#foo}}bar{{/foo}}", {knownHelpersOnly: true});
|
||||
it('Conditional blocks work in knownHelpers only mode', function() {
|
||||
var template = CompilerContext.compile('{{#foo}}bar{{/foo}}', {knownHelpersOnly: true});
|
||||
|
||||
var result = template({foo: 'baz'});
|
||||
equal(result, "bar", "'bar' should === '" + result);
|
||||
equal(result, 'bar', "'bar' should === '" + result);
|
||||
});
|
||||
it("Invert blocks work in knownHelpers only mode", function() {
|
||||
var template = CompilerContext.compile("{{^foo}}bar{{/foo}}", {knownHelpersOnly: true});
|
||||
it('Invert blocks work in knownHelpers only mode', function() {
|
||||
var template = CompilerContext.compile('{{^foo}}bar{{/foo}}', {knownHelpersOnly: true});
|
||||
|
||||
var result = template({foo: false});
|
||||
equal(result, "bar", "'bar' should === '" + result);
|
||||
equal(result, 'bar', "'bar' should === '" + result);
|
||||
});
|
||||
it("Functions are bound to the context in knownHelpers only mode", function() {
|
||||
var template = CompilerContext.compile("{{foo}}", {knownHelpersOnly: true});
|
||||
it('Functions are bound to the context in knownHelpers only mode', function() {
|
||||
var template = CompilerContext.compile('{{foo}}', {knownHelpersOnly: true});
|
||||
var result = template({foo: function() { return this.bar; }, bar: 'bar'});
|
||||
equal(result, "bar", "'bar' should === '" + result);
|
||||
equal(result, 'bar', "'bar' should === '" + result);
|
||||
});
|
||||
it("Unknown helper call in knownHelpers only mode should throw", function() {
|
||||
it('Unknown helper call in knownHelpers only mode should throw', function() {
|
||||
shouldThrow(function() {
|
||||
CompilerContext.compile("{{typeof hello}}", {knownHelpersOnly: true});
|
||||
CompilerContext.compile('{{typeof hello}}', {knownHelpersOnly: true});
|
||||
}, Error);
|
||||
});
|
||||
});
|
||||
|
||||
describe("blockHelperMissing", function() {
|
||||
it("lambdas are resolved by blockHelperMissing, not handlebars proper", function() {
|
||||
var string = "{{#truthy}}yep{{/truthy}}";
|
||||
describe('blockHelperMissing', function() {
|
||||
it('lambdas are resolved by blockHelperMissing, not handlebars proper', function() {
|
||||
var string = '{{#truthy}}yep{{/truthy}}';
|
||||
var data = { truthy: function() { return true; } };
|
||||
shouldCompileTo(string, data, "yep");
|
||||
shouldCompileTo(string, data, 'yep');
|
||||
});
|
||||
it("lambdas resolved by blockHelperMissing are bound to the context", function() {
|
||||
var string = "{{#truthy}}yep{{/truthy}}";
|
||||
it('lambdas resolved by blockHelperMissing are bound to the context', function() {
|
||||
var string = '{{#truthy}}yep{{/truthy}}';
|
||||
var boundData = { truthy: function() { return this.truthiness(); }, truthiness: function() { return false; } };
|
||||
shouldCompileTo(string, boundData, "");
|
||||
shouldCompileTo(string, boundData, '');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -528,13 +525,13 @@ describe('helpers', function() {
|
||||
var context = {};
|
||||
var helpers = {
|
||||
blockHelperMissing: function() {
|
||||
return 'missing: ' + arguments[arguments.length-1].name;
|
||||
return 'missing: ' + arguments[arguments.length - 1].name;
|
||||
},
|
||||
helperMissing: function() {
|
||||
return 'helper missing: ' + arguments[arguments.length-1].name;
|
||||
return 'helper missing: ' + arguments[arguments.length - 1].name;
|
||||
},
|
||||
helper: function() {
|
||||
return 'ran: ' + arguments[arguments.length-1].name;
|
||||
return 'ran: ' + arguments[arguments.length - 1].name;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -554,7 +551,7 @@ describe('helpers', function() {
|
||||
shouldCompileTo('{{#helper 1}}{{/helper}}', [context, helpers], 'ran: helper');
|
||||
});
|
||||
it('should include in known helper calls', function() {
|
||||
var template = CompilerContext.compile("{{helper}}", {knownHelpers: {'helper': true}, knownHelpersOnly: true});
|
||||
var template = CompilerContext.compile('{{helper}}', {knownHelpers: {'helper': true}, knownHelpersOnly: true});
|
||||
|
||||
equal(template({}, {helpers: helpers}), 'ran: helper');
|
||||
});
|
||||
@@ -569,8 +566,8 @@ describe('helpers', function() {
|
||||
});
|
||||
|
||||
describe('name conflicts', function() {
|
||||
it("helpers take precedence over same-named context properties", function() {
|
||||
var template = CompilerContext.compile("{{goodbye}} {{cruel world}}");
|
||||
it('helpers take precedence over same-named context properties', function() {
|
||||
var template = CompilerContext.compile('{{goodbye}} {{cruel world}}');
|
||||
|
||||
var helpers = {
|
||||
goodbye: function() {
|
||||
@@ -578,21 +575,21 @@ describe('helpers', function() {
|
||||
},
|
||||
|
||||
cruel: function(world) {
|
||||
return "cruel " + world.toUpperCase();
|
||||
return 'cruel ' + world.toUpperCase();
|
||||
}
|
||||
};
|
||||
|
||||
var context = {
|
||||
goodbye: "goodbye",
|
||||
world: "world"
|
||||
goodbye: 'goodbye',
|
||||
world: 'world'
|
||||
};
|
||||
|
||||
var result = template(context, {helpers: helpers});
|
||||
equals(result, "GOODBYE cruel WORLD", "Helper executed");
|
||||
equals(result, 'GOODBYE cruel WORLD', 'Helper executed');
|
||||
});
|
||||
|
||||
it("helpers take precedence over same-named context properties$", function() {
|
||||
var template = CompilerContext.compile("{{#goodbye}} {{cruel world}}{{/goodbye}}");
|
||||
it('helpers take precedence over same-named context properties$', function() {
|
||||
var template = CompilerContext.compile('{{#goodbye}} {{cruel world}}{{/goodbye}}');
|
||||
|
||||
var helpers = {
|
||||
goodbye: function(options) {
|
||||
@@ -600,21 +597,21 @@ describe('helpers', function() {
|
||||
},
|
||||
|
||||
cruel: function(world) {
|
||||
return "cruel " + world.toUpperCase();
|
||||
return 'cruel ' + world.toUpperCase();
|
||||
}
|
||||
};
|
||||
|
||||
var context = {
|
||||
goodbye: "goodbye",
|
||||
world: "world"
|
||||
goodbye: 'goodbye',
|
||||
world: 'world'
|
||||
};
|
||||
|
||||
var result = template(context, {helpers: helpers});
|
||||
equals(result, "GOODBYE cruel WORLD", "Helper executed");
|
||||
equals(result, 'GOODBYE cruel WORLD', 'Helper executed');
|
||||
});
|
||||
|
||||
it("Scoped names take precedence over helpers", function() {
|
||||
var template = CompilerContext.compile("{{this.goodbye}} {{cruel world}} {{cruel this.goodbye}}");
|
||||
it('Scoped names take precedence over helpers', function() {
|
||||
var template = CompilerContext.compile('{{this.goodbye}} {{cruel world}} {{cruel this.goodbye}}');
|
||||
|
||||
var helpers = {
|
||||
goodbye: function() {
|
||||
@@ -622,21 +619,21 @@ describe('helpers', function() {
|
||||
},
|
||||
|
||||
cruel: function(world) {
|
||||
return "cruel " + world.toUpperCase();
|
||||
return 'cruel ' + world.toUpperCase();
|
||||
}
|
||||
};
|
||||
|
||||
var context = {
|
||||
goodbye: "goodbye",
|
||||
world: "world"
|
||||
goodbye: 'goodbye',
|
||||
world: 'world'
|
||||
};
|
||||
|
||||
var result = template(context, {helpers: helpers});
|
||||
equals(result, "goodbye cruel WORLD cruel GOODBYE", "Helper not executed");
|
||||
equals(result, 'goodbye cruel WORLD cruel GOODBYE', 'Helper not executed');
|
||||
});
|
||||
|
||||
it("Scoped names take precedence over block helpers", function() {
|
||||
var template = CompilerContext.compile("{{#goodbye}} {{cruel world}}{{/goodbye}} {{this.goodbye}}");
|
||||
it('Scoped names take precedence over block helpers', function() {
|
||||
var template = CompilerContext.compile('{{#goodbye}} {{cruel world}}{{/goodbye}} {{this.goodbye}}');
|
||||
|
||||
var helpers = {
|
||||
goodbye: function(options) {
|
||||
@@ -644,17 +641,17 @@ describe('helpers', function() {
|
||||
},
|
||||
|
||||
cruel: function(world) {
|
||||
return "cruel " + world.toUpperCase();
|
||||
return 'cruel ' + world.toUpperCase();
|
||||
}
|
||||
};
|
||||
|
||||
var context = {
|
||||
goodbye: "goodbye",
|
||||
world: "world"
|
||||
goodbye: 'goodbye',
|
||||
world: 'world'
|
||||
};
|
||||
|
||||
var result = template(context, {helpers: helpers});
|
||||
equals(result, "GOODBYE cruel WORLD goodbye", "Helper executed");
|
||||
equals(result, 'GOODBYE cruel WORLD goodbye', 'Helper executed');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/*global Handlebars, beforeEach, handlebarsEnv, shouldCompileTo */
|
||||
describe('javascript-compiler api', function() {
|
||||
if (!Handlebars.JavaScriptCompiler) {
|
||||
return;
|
||||
@@ -17,13 +16,15 @@ describe('javascript-compiler api', function() {
|
||||
handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = function(parent, name) {
|
||||
return parent + '.bar_' + name;
|
||||
};
|
||||
shouldCompileTo("{{foo}}", { bar_foo: "food" }, "food");
|
||||
/*eslint-disable camelcase */
|
||||
shouldCompileTo('{{foo}}', { bar_foo: 'food' }, 'food');
|
||||
/*eslint-enable camelcase */
|
||||
});
|
||||
|
||||
// Tests nameLookup dot vs. bracket behavior. Bracket is required in certain cases
|
||||
// to avoid errors in older browsers.
|
||||
it('should handle reserved words', function() {
|
||||
shouldCompileTo("{{foo}} {{~null~}}", { foo: "food" }, "food");
|
||||
shouldCompileTo('{{foo}} {{~null~}}', { foo: 'food' }, 'food');
|
||||
});
|
||||
});
|
||||
describe('#compilerInfo', function() {
|
||||
@@ -45,7 +46,7 @@ describe('javascript-compiler api', function() {
|
||||
throw new Error('It didn\'t work');
|
||||
}
|
||||
};
|
||||
shouldCompileTo("{{foo}} ", { foo: "food" }, "food ");
|
||||
shouldCompileTo('{{foo}} ', { foo: 'food' }, 'food ');
|
||||
});
|
||||
});
|
||||
describe('buffer', function() {
|
||||
@@ -65,13 +66,13 @@ describe('javascript-compiler api', function() {
|
||||
handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer = function() {
|
||||
return this.quotedString('foo_');
|
||||
};
|
||||
shouldCompileTo("{{foo}} ", { foo: "food" }, "foo_food ");
|
||||
shouldCompileTo('{{foo}} ', { foo: 'food' }, 'foo_food ');
|
||||
});
|
||||
it('should allow append buffer override', function() {
|
||||
handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = function(string) {
|
||||
return $superAppend.call(this, [string, ' + "_foo"']);
|
||||
};
|
||||
shouldCompileTo("{{foo}}", { foo: "food" }, "food_foo");
|
||||
shouldCompileTo('{{foo}}', { foo: 'food' }, 'food_foo');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+74
-75
@@ -1,235 +1,234 @@
|
||||
/*global Handlebars, shouldThrow */
|
||||
describe('parser', function() {
|
||||
if (!Handlebars.print) {
|
||||
return;
|
||||
}
|
||||
|
||||
function ast_for(template) {
|
||||
function astFor(template) {
|
||||
var ast = Handlebars.parse(template);
|
||||
return Handlebars.print(ast);
|
||||
}
|
||||
|
||||
it('parses simple mustaches', function() {
|
||||
equals(ast_for('{{123}}'), "{{ NUMBER{123} [] }}\n");
|
||||
equals(ast_for('{{"foo"}}'), '{{ "foo" [] }}\n');
|
||||
equals(ast_for('{{false}}'), '{{ BOOLEAN{false} [] }}\n');
|
||||
equals(ast_for('{{true}}'), '{{ BOOLEAN{true} [] }}\n');
|
||||
equals(ast_for('{{foo}}'), "{{ PATH:foo [] }}\n");
|
||||
equals(ast_for('{{foo?}}'), "{{ PATH:foo? [] }}\n");
|
||||
equals(ast_for('{{foo_}}'), "{{ PATH:foo_ [] }}\n");
|
||||
equals(ast_for('{{foo-}}'), "{{ PATH:foo- [] }}\n");
|
||||
equals(ast_for('{{foo:}}'), "{{ PATH:foo: [] }}\n");
|
||||
equals(astFor('{{123}}'), '{{ NUMBER{123} [] }}\n');
|
||||
equals(astFor('{{"foo"}}'), '{{ "foo" [] }}\n');
|
||||
equals(astFor('{{false}}'), '{{ BOOLEAN{false} [] }}\n');
|
||||
equals(astFor('{{true}}'), '{{ BOOLEAN{true} [] }}\n');
|
||||
equals(astFor('{{foo}}'), '{{ PATH:foo [] }}\n');
|
||||
equals(astFor('{{foo?}}'), '{{ PATH:foo? [] }}\n');
|
||||
equals(astFor('{{foo_}}'), '{{ PATH:foo_ [] }}\n');
|
||||
equals(astFor('{{foo-}}'), '{{ PATH:foo- [] }}\n');
|
||||
equals(astFor('{{foo:}}'), '{{ PATH:foo: [] }}\n');
|
||||
});
|
||||
|
||||
it('parses simple mustaches with data', function() {
|
||||
equals(ast_for("{{@foo}}"), "{{ @PATH:foo [] }}\n");
|
||||
equals(astFor('{{@foo}}'), '{{ @PATH:foo [] }}\n');
|
||||
});
|
||||
|
||||
it('parses simple mustaches with data paths', function() {
|
||||
equals(ast_for("{{@../foo}}"), "{{ @PATH:foo [] }}\n");
|
||||
equals(astFor('{{@../foo}}'), '{{ @PATH:foo [] }}\n');
|
||||
});
|
||||
|
||||
it('parses mustaches with paths', function() {
|
||||
equals(ast_for("{{foo/bar}}"), "{{ PATH:foo/bar [] }}\n");
|
||||
equals(astFor('{{foo/bar}}'), '{{ PATH:foo/bar [] }}\n');
|
||||
});
|
||||
|
||||
it('parses mustaches with this/foo', function() {
|
||||
equals(ast_for("{{this/foo}}"), "{{ PATH:foo [] }}\n");
|
||||
equals(astFor('{{this/foo}}'), '{{ PATH:foo [] }}\n');
|
||||
});
|
||||
|
||||
it('parses mustaches with - in a path', function() {
|
||||
equals(ast_for("{{foo-bar}}"), "{{ PATH:foo-bar [] }}\n");
|
||||
equals(astFor('{{foo-bar}}'), '{{ PATH:foo-bar [] }}\n');
|
||||
});
|
||||
|
||||
it('parses mustaches with parameters', function() {
|
||||
equals(ast_for("{{foo bar}}"), "{{ PATH:foo [PATH:bar] }}\n");
|
||||
equals(astFor('{{foo bar}}'), '{{ PATH:foo [PATH:bar] }}\n');
|
||||
});
|
||||
|
||||
it('parses mustaches with string parameters', function() {
|
||||
equals(ast_for("{{foo bar \"baz\" }}"), '{{ PATH:foo [PATH:bar, "baz"] }}\n');
|
||||
equals(astFor('{{foo bar \"baz\" }}'), '{{ PATH:foo [PATH:bar, "baz"] }}\n');
|
||||
});
|
||||
|
||||
it('parses mustaches with NUMBER parameters', function() {
|
||||
equals(ast_for("{{foo 1}}"), "{{ PATH:foo [NUMBER{1}] }}\n");
|
||||
equals(astFor('{{foo 1}}'), '{{ PATH:foo [NUMBER{1}] }}\n');
|
||||
});
|
||||
|
||||
it('parses mustaches with BOOLEAN parameters', function() {
|
||||
equals(ast_for("{{foo true}}"), "{{ PATH:foo [BOOLEAN{true}] }}\n");
|
||||
equals(ast_for("{{foo false}}"), "{{ PATH:foo [BOOLEAN{false}] }}\n");
|
||||
equals(astFor('{{foo true}}'), '{{ PATH:foo [BOOLEAN{true}] }}\n');
|
||||
equals(astFor('{{foo false}}'), '{{ PATH:foo [BOOLEAN{false}] }}\n');
|
||||
});
|
||||
|
||||
it('parses mustaches with undefined and null paths', function() {
|
||||
equals(ast_for("{{undefined}}"), "{{ UNDEFINED [] }}\n");
|
||||
equals(ast_for("{{null}}"), "{{ NULL [] }}\n");
|
||||
equals(astFor('{{undefined}}'), '{{ UNDEFINED [] }}\n');
|
||||
equals(astFor('{{null}}'), '{{ NULL [] }}\n');
|
||||
});
|
||||
it('parses mustaches with undefined and null parameters', function() {
|
||||
equals(ast_for("{{foo undefined null}}"), "{{ PATH:foo [UNDEFINED, NULL] }}\n");
|
||||
equals(astFor('{{foo undefined null}}'), '{{ PATH:foo [UNDEFINED, NULL] }}\n');
|
||||
});
|
||||
|
||||
it('parses mutaches with DATA parameters', function() {
|
||||
equals(ast_for("{{foo @bar}}"), "{{ PATH:foo [@PATH:bar] }}\n");
|
||||
equals(astFor('{{foo @bar}}'), '{{ PATH:foo [@PATH:bar] }}\n');
|
||||
});
|
||||
|
||||
it('parses mustaches with hash arguments', function() {
|
||||
equals(ast_for("{{foo bar=baz}}"), "{{ PATH:foo [] HASH{bar=PATH:baz} }}\n");
|
||||
equals(ast_for("{{foo bar=1}}"), "{{ PATH:foo [] HASH{bar=NUMBER{1}} }}\n");
|
||||
equals(ast_for("{{foo bar=true}}"), "{{ PATH:foo [] HASH{bar=BOOLEAN{true}} }}\n");
|
||||
equals(ast_for("{{foo bar=false}}"), "{{ PATH:foo [] HASH{bar=BOOLEAN{false}} }}\n");
|
||||
equals(ast_for("{{foo bar=@baz}}"), "{{ PATH:foo [] HASH{bar=@PATH:baz} }}\n");
|
||||
equals(astFor('{{foo bar=baz}}'), '{{ PATH:foo [] HASH{bar=PATH:baz} }}\n');
|
||||
equals(astFor('{{foo bar=1}}'), '{{ PATH:foo [] HASH{bar=NUMBER{1}} }}\n');
|
||||
equals(astFor('{{foo bar=true}}'), '{{ PATH:foo [] HASH{bar=BOOLEAN{true}} }}\n');
|
||||
equals(astFor('{{foo bar=false}}'), '{{ PATH:foo [] HASH{bar=BOOLEAN{false}} }}\n');
|
||||
equals(astFor('{{foo bar=@baz}}'), '{{ PATH:foo [] HASH{bar=@PATH:baz} }}\n');
|
||||
|
||||
equals(ast_for("{{foo bar=baz bat=bam}}"), "{{ PATH:foo [] HASH{bar=PATH:baz, bat=PATH:bam} }}\n");
|
||||
equals(ast_for("{{foo bar=baz bat=\"bam\"}}"), '{{ PATH:foo [] HASH{bar=PATH:baz, bat="bam"} }}\n');
|
||||
equals(astFor('{{foo bar=baz bat=bam}}'), '{{ PATH:foo [] HASH{bar=PATH:baz, bat=PATH:bam} }}\n');
|
||||
equals(astFor('{{foo bar=baz bat="bam"}}'), '{{ PATH:foo [] HASH{bar=PATH:baz, bat="bam"} }}\n');
|
||||
|
||||
equals(ast_for("{{foo bat='bam'}}"), '{{ PATH:foo [] HASH{bat="bam"} }}\n');
|
||||
equals(astFor("{{foo bat='bam'}}"), '{{ PATH:foo [] HASH{bat="bam"} }}\n');
|
||||
|
||||
equals(ast_for("{{foo omg bar=baz bat=\"bam\"}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n');
|
||||
equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=1}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n');
|
||||
equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=true}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n');
|
||||
equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=false}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n');
|
||||
equals(astFor('{{foo omg bar=baz bat=\"bam\"}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n');
|
||||
equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=1}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n');
|
||||
equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=true}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n');
|
||||
equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=false}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n');
|
||||
});
|
||||
|
||||
it('parses contents followed by a mustache', function() {
|
||||
equals(ast_for("foo bar {{baz}}"), "CONTENT[ \'foo bar \' ]\n{{ PATH:baz [] }}\n");
|
||||
equals(astFor('foo bar {{baz}}'), 'CONTENT[ \'foo bar \' ]\n{{ PATH:baz [] }}\n');
|
||||
});
|
||||
|
||||
it('parses a partial', function() {
|
||||
equals(ast_for("{{> foo }}"), "{{> PARTIAL:foo }}\n");
|
||||
equals(ast_for("{{> 'foo' }}"), "{{> PARTIAL:foo }}\n");
|
||||
equals(ast_for("{{> 1 }}"), "{{> PARTIAL:1 }}\n");
|
||||
equals(astFor('{{> foo }}'), '{{> PARTIAL:foo }}\n');
|
||||
equals(astFor('{{> "foo" }}'), '{{> PARTIAL:foo }}\n');
|
||||
equals(astFor('{{> 1 }}'), '{{> PARTIAL:1 }}\n');
|
||||
});
|
||||
|
||||
it('parses a partial with context', function() {
|
||||
equals(ast_for("{{> foo bar}}"), "{{> PARTIAL:foo PATH:bar }}\n");
|
||||
equals(astFor('{{> foo bar}}'), '{{> PARTIAL:foo PATH:bar }}\n');
|
||||
});
|
||||
|
||||
it('parses a partial with hash', function() {
|
||||
equals(ast_for("{{> foo bar=bat}}"), "{{> PARTIAL:foo HASH{bar=PATH:bat} }}\n");
|
||||
equals(astFor('{{> foo bar=bat}}'), '{{> PARTIAL:foo HASH{bar=PATH:bat} }}\n');
|
||||
});
|
||||
|
||||
it('parses a partial with context and hash', function() {
|
||||
equals(ast_for("{{> foo bar bat=baz}}"), "{{> PARTIAL:foo PATH:bar HASH{bat=PATH:baz} }}\n");
|
||||
equals(astFor('{{> foo bar bat=baz}}'), '{{> PARTIAL:foo PATH:bar HASH{bat=PATH:baz} }}\n');
|
||||
});
|
||||
|
||||
it('parses a partial with a complex name', function() {
|
||||
equals(ast_for("{{> shared/partial?.bar}}"), "{{> PARTIAL:shared/partial?.bar }}\n");
|
||||
equals(astFor('{{> shared/partial?.bar}}'), '{{> PARTIAL:shared/partial?.bar }}\n');
|
||||
});
|
||||
|
||||
it('parses a comment', function() {
|
||||
equals(ast_for("{{! this is a comment }}"), "{{! ' this is a comment ' }}\n");
|
||||
equals(astFor('{{! this is a comment }}'), "{{! ' this is a comment ' }}\n");
|
||||
});
|
||||
|
||||
it('parses a multi-line comment', function() {
|
||||
equals(ast_for("{{!\nthis is a multi-line comment\n}}"), "{{! \'\nthis is a multi-line comment\n\' }}\n");
|
||||
equals(astFor('{{!\nthis is a multi-line comment\n}}'), "{{! \'\nthis is a multi-line comment\n\' }}\n");
|
||||
});
|
||||
|
||||
it('parses an inverse section', function() {
|
||||
equals(ast_for("{{#foo}} bar {{^}} baz {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
||||
equals(astFor('{{#foo}} bar {{^}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
||||
});
|
||||
|
||||
it('parses an inverse (else-style) section', function() {
|
||||
equals(ast_for("{{#foo}} bar {{else}} baz {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
||||
equals(astFor('{{#foo}} bar {{else}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
||||
});
|
||||
|
||||
it('parses multiple inverse sections', function() {
|
||||
equals(ast_for("{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n BLOCK:\n PATH:if [PATH:bar]\n PROGRAM:\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
||||
equals(astFor('{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n BLOCK:\n PATH:if [PATH:bar]\n PROGRAM:\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
||||
});
|
||||
|
||||
it('parses empty blocks', function() {
|
||||
equals(ast_for("{{#foo}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n");
|
||||
equals(astFor('{{#foo}}{{/foo}}'), 'BLOCK:\n PATH:foo []\n PROGRAM:\n');
|
||||
});
|
||||
|
||||
it('parses empty blocks with empty inverse section', function() {
|
||||
equals(ast_for("{{#foo}}{{^}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n");
|
||||
equals(astFor('{{#foo}}{{^}}{{/foo}}'), 'BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n');
|
||||
});
|
||||
|
||||
it('parses empty blocks with empty inverse (else-style) section', function() {
|
||||
equals(ast_for("{{#foo}}{{else}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n");
|
||||
equals(astFor('{{#foo}}{{else}}{{/foo}}'), 'BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n');
|
||||
});
|
||||
|
||||
it('parses non-empty blocks with empty inverse section', function() {
|
||||
equals(ast_for("{{#foo}} bar {{^}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
|
||||
equals(astFor('{{#foo}} bar {{^}}{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
|
||||
});
|
||||
|
||||
it('parses non-empty blocks with empty inverse (else-style) section', function() {
|
||||
equals(ast_for("{{#foo}} bar {{else}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
|
||||
equals(astFor('{{#foo}} bar {{else}}{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
|
||||
});
|
||||
|
||||
it('parses empty blocks with non-empty inverse section', function() {
|
||||
equals(ast_for("{{#foo}}{{^}} bar {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
|
||||
equals(astFor('{{#foo}}{{^}} bar {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
|
||||
});
|
||||
|
||||
it('parses empty blocks with non-empty inverse (else-style) section', function() {
|
||||
equals(ast_for("{{#foo}}{{else}} bar {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
|
||||
equals(astFor('{{#foo}}{{else}} bar {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
|
||||
});
|
||||
|
||||
it('parses a standalone inverse section', function() {
|
||||
equals(ast_for("{{^foo}}bar{{/foo}}"), "BLOCK:\n PATH:foo []\n {{^}}\n CONTENT[ 'bar' ]\n");
|
||||
equals(astFor('{{^foo}}bar{{/foo}}'), "BLOCK:\n PATH:foo []\n {{^}}\n CONTENT[ 'bar' ]\n");
|
||||
});
|
||||
it('throws on old inverse section', function() {
|
||||
shouldThrow(function() {
|
||||
ast_for("{{else foo}}bar{{/foo}}");
|
||||
astFor('{{else foo}}bar{{/foo}}');
|
||||
}, Error);
|
||||
});
|
||||
|
||||
it('parses block with block params', function() {
|
||||
equals(ast_for("{{#foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
||||
equals(astFor('{{#foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
||||
});
|
||||
|
||||
it('parses inverse block with block params', function() {
|
||||
equals(ast_for("{{^foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n PATH:foo []\n {{^}}\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
||||
equals(astFor('{{^foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n {{^}}\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
||||
});
|
||||
it('parses chained inverse block with block params', function() {
|
||||
equals(ast_for("{{#foo}}{{else foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
||||
equals(astFor('{{#foo}}{{else foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
||||
});
|
||||
it("raises if there's a Parse error", function() {
|
||||
it('raises if there\'s a Parse error', function() {
|
||||
shouldThrow(function() {
|
||||
ast_for("foo{{^}}bar");
|
||||
astFor('foo{{^}}bar');
|
||||
}, Error, /Parse error on line 1/);
|
||||
shouldThrow(function() {
|
||||
ast_for("{{foo}");
|
||||
astFor('{{foo}');
|
||||
}, Error, /Parse error on line 1/);
|
||||
shouldThrow(function() {
|
||||
ast_for("{{foo &}}");
|
||||
astFor('{{foo &}}');
|
||||
}, Error, /Parse error on line 1/);
|
||||
shouldThrow(function() {
|
||||
ast_for("{{#goodbyes}}{{/hellos}}");
|
||||
astFor('{{#goodbyes}}{{/hellos}}');
|
||||
}, Error, /goodbyes doesn't match hellos/);
|
||||
|
||||
shouldThrow(function() {
|
||||
ast_for("{{{{goodbyes}}}} {{{{/hellos}}}}");
|
||||
astFor('{{{{goodbyes}}}} {{{{/hellos}}}}');
|
||||
}, Error, /goodbyes doesn't match hellos/);
|
||||
});
|
||||
|
||||
it('should handle invalid paths', function() {
|
||||
shouldThrow(function() {
|
||||
ast_for("{{foo/../bar}}");
|
||||
astFor('{{foo/../bar}}');
|
||||
}, Error, /Invalid path: foo\/\.\. - 1:2/);
|
||||
shouldThrow(function() {
|
||||
ast_for("{{foo/./bar}}");
|
||||
astFor('{{foo/./bar}}');
|
||||
}, Error, /Invalid path: foo\/\. - 1:2/);
|
||||
shouldThrow(function() {
|
||||
ast_for("{{foo/this/bar}}");
|
||||
astFor('{{foo/this/bar}}');
|
||||
}, Error, /Invalid path: foo\/this - 1:2/);
|
||||
});
|
||||
|
||||
it('knows how to report the correct line number in errors', function() {
|
||||
shouldThrow(function() {
|
||||
ast_for("hello\nmy\n{{foo}");
|
||||
astFor('hello\nmy\n{{foo}');
|
||||
}, Error, /Parse error on line 3/);
|
||||
shouldThrow(function() {
|
||||
ast_for("hello\n\nmy\n\n{{foo}");
|
||||
astFor('hello\n\nmy\n\n{{foo}');
|
||||
}, Error, /Parse error on line 5/);
|
||||
});
|
||||
|
||||
it('knows how to report the correct line number in errors when the first character is a newline', function() {
|
||||
shouldThrow(function() {
|
||||
ast_for("\n\nhello\n\nmy\n\n{{foo}");
|
||||
astFor('\n\nhello\n\nmy\n\n{{foo}');
|
||||
}, Error, /Parse error on line 7/);
|
||||
});
|
||||
|
||||
describe('externally compiled AST', function() {
|
||||
it('can pass through an already-compiled AST', function() {
|
||||
equals(ast_for(new Handlebars.AST.Program([new Handlebars.AST.ContentStatement("Hello")], null)), "CONTENT[ \'Hello\' ]\n");
|
||||
equals(astFor(new Handlebars.AST.Program([new Handlebars.AST.ContentStatement('Hello')], null)), 'CONTENT[ \'Hello\' ]\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+106
-107
@@ -1,11 +1,10 @@
|
||||
/*global CompilerContext, Handlebars, handlebarsEnv, shouldCompileTo, shouldCompileToWithPartials, shouldThrow */
|
||||
describe('partials', function() {
|
||||
it('basic partials', function() {
|
||||
var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
|
||||
var partial = '{{name}} ({{url}}) ';
|
||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial},,false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial},, false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
|
||||
});
|
||||
|
||||
it('dynamic partials', function() {
|
||||
@@ -18,7 +17,7 @@ describe('partials', function() {
|
||||
}
|
||||
};
|
||||
shouldCompileToWithPartials(string, [hash, helpers, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
|
||||
shouldCompileToWithPartials(string, [hash, helpers, {dude: partial},,false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
|
||||
shouldCompileToWithPartials(string, [hash, helpers, {dude: partial},, false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
|
||||
});
|
||||
it('failing dynamic partials', function() {
|
||||
var string = 'Dudes: {{#dudes}}{{> (partial)}}{{/dudes}}';
|
||||
@@ -34,19 +33,19 @@ describe('partials', function() {
|
||||
}, Handlebars.Exception, 'The partial missing could not be found');
|
||||
});
|
||||
|
||||
it("partials with context", function() {
|
||||
var string = "Dudes: {{>dude dudes}}";
|
||||
var partial = "{{#this}}{{name}} ({{url}}) {{/this}}";
|
||||
var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes: Yehuda (http://yehuda) Alan (http://alan) ",
|
||||
"Partials can be passed a context");
|
||||
it('partials with context', function() {
|
||||
var string = 'Dudes: {{>dude dudes}}';
|
||||
var partial = '{{#this}}{{name}} ({{url}}) {{/this}}';
|
||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ',
|
||||
'Partials can be passed a context');
|
||||
});
|
||||
|
||||
it("partials with undefined context", function() {
|
||||
var string = "Dudes: {{>dude dudes}}";
|
||||
var partial = "{{foo}} Empty";
|
||||
it('partials with undefined context', function() {
|
||||
var string = 'Dudes: {{>dude dudes}}';
|
||||
var partial = '{{foo}} Empty';
|
||||
var hash = {};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes: Empty");
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: Empty');
|
||||
});
|
||||
|
||||
it('partials with duplicate parameters', function() {
|
||||
@@ -55,133 +54,133 @@ describe('partials', function() {
|
||||
}, Error, 'Unsupported number of partial arguments: 2 - 1:7');
|
||||
});
|
||||
|
||||
it("partials with parameters", function() {
|
||||
var string = "Dudes: {{#dudes}}{{> dude others=..}}{{/dudes}}";
|
||||
var partial = "{{others.foo}}{{name}} ({{url}}) ";
|
||||
var hash = {foo: 'bar', dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes: barYehuda (http://yehuda) barAlan (http://alan) ",
|
||||
"Basic partials output based on current context.");
|
||||
it('partials with parameters', function() {
|
||||
var string = 'Dudes: {{#dudes}}{{> dude others=..}}{{/dudes}}';
|
||||
var partial = '{{others.foo}}{{name}} ({{url}}) ';
|
||||
var hash = {foo: 'bar', dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: barYehuda (http://yehuda) barAlan (http://alan) ',
|
||||
'Basic partials output based on current context.');
|
||||
});
|
||||
|
||||
it("partial in a partial", function() {
|
||||
var string = "Dudes: {{#dudes}}{{>dude}}{{/dudes}}";
|
||||
var dude = "{{name}} {{> url}} ";
|
||||
var url = "<a href='{{url}}'>{{url}}</a>";
|
||||
var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}], true, "Dudes: Yehuda <a href='http://yehuda'>http://yehuda</a> Alan <a href='http://alan'>http://alan</a> ", "Partials are rendered inside of other partials");
|
||||
it('partial in a partial', function() {
|
||||
var string = 'Dudes: {{#dudes}}{{>dude}}{{/dudes}}';
|
||||
var dude = '{{name}} {{> url}} ';
|
||||
var url = '<a href="{{url}}">{{url}}</a>';
|
||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}], true, 'Dudes: Yehuda <a href="http://yehuda">http://yehuda</a> Alan <a href="http://alan">http://alan</a> ', 'Partials are rendered inside of other partials');
|
||||
});
|
||||
|
||||
it("rendering undefined partial throws an exception", function() {
|
||||
it('rendering undefined partial throws an exception', function() {
|
||||
shouldThrow(function() {
|
||||
var template = CompilerContext.compile("{{> whatever}}");
|
||||
var template = CompilerContext.compile('{{> whatever}}');
|
||||
template();
|
||||
}, Handlebars.Exception, 'The partial whatever could not be found');
|
||||
});
|
||||
|
||||
it("registering undefined partial throws an exception", function() {
|
||||
it('registering undefined partial throws an exception', function() {
|
||||
shouldThrow(function() {
|
||||
var undef;
|
||||
handlebarsEnv.registerPartial('undefined_test', undef);
|
||||
}, Handlebars.Exception, 'Attempting to register a partial as undefined');
|
||||
});
|
||||
|
||||
it("rendering template partial in vm mode throws an exception", function() {
|
||||
it('rendering template partial in vm mode throws an exception', function() {
|
||||
shouldThrow(function() {
|
||||
var template = CompilerContext.compile("{{> whatever}}");
|
||||
var template = CompilerContext.compile('{{> whatever}}');
|
||||
template();
|
||||
}, Handlebars.Exception, 'The partial whatever could not be found');
|
||||
});
|
||||
|
||||
it("rendering function partial in vm mode", function() {
|
||||
var string = "Dudes: {{#dudes}}{{> dude}}{{/dudes}}";
|
||||
var partial = function(context) {
|
||||
it('rendering function partial in vm mode', function() {
|
||||
var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
|
||||
function partial(context) {
|
||||
return context.name + ' (' + context.url + ') ';
|
||||
};
|
||||
var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
|
||||
shouldCompileTo(string, [hash, {}, {dude: partial}], "Dudes: Yehuda (http://yehuda) Alan (http://alan) ",
|
||||
"Function partials output based in VM.");
|
||||
}
|
||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
shouldCompileTo(string, [hash, {}, {dude: partial}], 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ',
|
||||
'Function partials output based in VM.');
|
||||
});
|
||||
|
||||
it("GH-14: a partial preceding a selector", function() {
|
||||
var string = "Dudes: {{>dude}} {{another_dude}}";
|
||||
var dude = "{{name}}";
|
||||
var hash = {name:"Jeepers", another_dude:"Creepers"};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude:dude}], true, "Dudes: Jeepers Creepers", "Regular selectors can follow a partial");
|
||||
it('GH-14: a partial preceding a selector', function() {
|
||||
var string = 'Dudes: {{>dude}} {{anotherDude}}';
|
||||
var dude = '{{name}}';
|
||||
var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: dude}], true, 'Dudes: Jeepers Creepers', 'Regular selectors can follow a partial');
|
||||
});
|
||||
|
||||
it("Partials with slash paths", function() {
|
||||
var string = "Dudes: {{> shared/dude}}";
|
||||
var dude = "{{name}}";
|
||||
var hash = {name:"Jeepers", another_dude:"Creepers"};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude':dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
|
||||
it('Partials with slash paths', function() {
|
||||
var string = 'Dudes: {{> shared/dude}}';
|
||||
var dude = '{{name}}';
|
||||
var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
|
||||
});
|
||||
|
||||
it("Partials with slash and point paths", function() {
|
||||
var string = "Dudes: {{> shared/dude.thing}}";
|
||||
var dude = "{{name}}";
|
||||
var hash = {name:"Jeepers", another_dude:"Creepers"};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude.thing':dude}], true, "Dudes: Jeepers", "Partials can use literal with points in paths");
|
||||
it('Partials with slash and point paths', function() {
|
||||
var string = 'Dudes: {{> shared/dude.thing}}';
|
||||
var dude = '{{name}}';
|
||||
var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude.thing': dude}], true, 'Dudes: Jeepers', 'Partials can use literal with points in paths');
|
||||
});
|
||||
|
||||
it("Global Partials", function() {
|
||||
handlebarsEnv.registerPartial('global_test', '{{another_dude}}');
|
||||
it('Global Partials', function() {
|
||||
handlebarsEnv.registerPartial('globalTest', '{{anotherDude}}');
|
||||
|
||||
var string = "Dudes: {{> shared/dude}} {{> global_test}}";
|
||||
var dude = "{{name}}";
|
||||
var hash = {name:"Jeepers", another_dude:"Creepers"};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude':dude}], true, "Dudes: Jeepers Creepers", "Partials can use globals or passed");
|
||||
var string = 'Dudes: {{> shared/dude}} {{> globalTest}}';
|
||||
var dude = '{{name}}';
|
||||
var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude': dude}], true, 'Dudes: Jeepers Creepers', 'Partials can use globals or passed');
|
||||
|
||||
handlebarsEnv.unregisterPartial('global_test');
|
||||
equals(handlebarsEnv.partials.global_test, undefined);
|
||||
handlebarsEnv.unregisterPartial('globalTest');
|
||||
equals(handlebarsEnv.partials.globalTest, undefined);
|
||||
});
|
||||
|
||||
it("Multiple partial registration", function() {
|
||||
it('Multiple partial registration', function() {
|
||||
handlebarsEnv.registerPartial({
|
||||
'shared/dude': '{{name}}',
|
||||
global_test: '{{another_dude}}'
|
||||
globalTest: '{{anotherDude}}'
|
||||
});
|
||||
|
||||
var string = "Dudes: {{> shared/dude}} {{> global_test}}";
|
||||
var hash = {name:"Jeepers", another_dude:"Creepers"};
|
||||
shouldCompileToWithPartials(string, [hash], true, "Dudes: Jeepers Creepers", "Partials can use globals or passed");
|
||||
var string = 'Dudes: {{> shared/dude}} {{> globalTest}}';
|
||||
var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
|
||||
shouldCompileToWithPartials(string, [hash], true, 'Dudes: Jeepers Creepers', 'Partials can use globals or passed');
|
||||
});
|
||||
|
||||
it("Partials with integer path", function() {
|
||||
var string = "Dudes: {{> 404}}";
|
||||
var dude = "{{name}}";
|
||||
var hash = {name:"Jeepers", another_dude:"Creepers"};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {404:dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
|
||||
it('Partials with integer path', function() {
|
||||
var string = 'Dudes: {{> 404}}';
|
||||
var dude = '{{name}}';
|
||||
var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {404: dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
|
||||
});
|
||||
|
||||
it("Partials with complex path", function() {
|
||||
var string = "Dudes: {{> 404/asdf?.bar}}";
|
||||
var dude = "{{name}}";
|
||||
var hash = {name:"Jeepers", another_dude:"Creepers"};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'404/asdf?.bar':dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
|
||||
it('Partials with complex path', function() {
|
||||
var string = 'Dudes: {{> 404/asdf?.bar}}';
|
||||
var dude = '{{name}}';
|
||||
var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
|
||||
});
|
||||
|
||||
it("Partials with escaped", function() {
|
||||
var string = "Dudes: {{> [+404/asdf?.bar]}}";
|
||||
var dude = "{{name}}";
|
||||
var hash = {name:"Jeepers", another_dude:"Creepers"};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar':dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
|
||||
it('Partials with escaped', function() {
|
||||
var string = 'Dudes: {{> [+404/asdf?.bar]}}';
|
||||
var dude = '{{name}}';
|
||||
var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
|
||||
});
|
||||
|
||||
it("Partials with string", function() {
|
||||
var string = "Dudes: {{> \"+404/asdf?.bar\"}}";
|
||||
var dude = "{{name}}";
|
||||
var hash = {name:"Jeepers", another_dude:"Creepers"};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar':dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
|
||||
it('Partials with string', function() {
|
||||
var string = 'Dudes: {{> \'+404/asdf?.bar\'}}';
|
||||
var dude = '{{name}}';
|
||||
var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
|
||||
});
|
||||
|
||||
it('should handle empty partial', function() {
|
||||
var string = "Dudes: {{#dudes}}{{> dude}}{{/dudes}}";
|
||||
var partial = "";
|
||||
var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes: ");
|
||||
var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
|
||||
var partial = '';
|
||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: ');
|
||||
});
|
||||
|
||||
it("throw on missing partial", function() {
|
||||
it('throw on missing partial', function() {
|
||||
var compile = handlebarsEnv.compile;
|
||||
handlebarsEnv.compile = undefined;
|
||||
shouldThrow(function() {
|
||||
@@ -200,28 +199,28 @@ describe('partials', function() {
|
||||
});
|
||||
|
||||
describe('standalone partials', function() {
|
||||
it("indented partials", function() {
|
||||
var string = "Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}";
|
||||
var dude = "{{name}}\n";
|
||||
var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
|
||||
it('indented partials', function() {
|
||||
var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}';
|
||||
var dude = '{{name}}\n';
|
||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: dude}], true,
|
||||
"Dudes:\n Yehuda\n Alan\n");
|
||||
'Dudes:\n Yehuda\n Alan\n');
|
||||
});
|
||||
it("nested indented partials", function() {
|
||||
var string = "Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}";
|
||||
var dude = "{{name}}\n {{> url}}";
|
||||
var url = "{{url}}!\n";
|
||||
var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
|
||||
it('nested indented partials', function() {
|
||||
var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}';
|
||||
var dude = '{{name}}\n {{> url}}';
|
||||
var url = '{{url}}!\n';
|
||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}], true,
|
||||
"Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n");
|
||||
'Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n');
|
||||
});
|
||||
it("prevent nested indented partials", function() {
|
||||
var string = "Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}";
|
||||
var dude = "{{name}}\n {{> url}}";
|
||||
var url = "{{url}}!\n";
|
||||
var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
|
||||
it('prevent nested indented partials', function() {
|
||||
var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}';
|
||||
var dude = '{{name}}\n {{> url}}';
|
||||
var url = '{{url}}!\n';
|
||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}, {preventIndent: true}], true,
|
||||
"Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n");
|
||||
'Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
/*global shouldThrow */
|
||||
|
||||
|
||||
/*eslint-disable no-console */
|
||||
describe('precompiler', function() {
|
||||
// NOP Under non-node environments
|
||||
if (typeof process === 'undefined') {
|
||||
|
||||
+43
-33
@@ -1,26 +1,34 @@
|
||||
/*global CompilerContext, shouldCompileTo, shouldThrow */
|
||||
describe('Regressions', function() {
|
||||
it("GH-94: Cannot read property of undefined", function() {
|
||||
var data = {"books":[{"title":"The origin of species","author":{"name":"Charles Darwin"}},{"title":"Lazarillo de Tormes"}]};
|
||||
var string = "{{#books}}{{title}}{{author.name}}{{/books}}";
|
||||
shouldCompileTo(string, data, "The origin of speciesCharles DarwinLazarillo de Tormes",
|
||||
"Renders without an undefined property error");
|
||||
it('GH-94: Cannot read property of undefined', function() {
|
||||
var data = {
|
||||
'books': [{
|
||||
'title': 'The origin of species',
|
||||
'author': {
|
||||
'name': 'Charles Darwin'
|
||||
}
|
||||
}, {
|
||||
'title': 'Lazarillo de Tormes'
|
||||
}]
|
||||
};
|
||||
var string = '{{#books}}{{title}}{{author.name}}{{/books}}';
|
||||
shouldCompileTo(string, data, 'The origin of speciesCharles DarwinLazarillo de Tormes',
|
||||
'Renders without an undefined property error');
|
||||
});
|
||||
|
||||
it("GH-150: Inverted sections print when they shouldn't", function() {
|
||||
var string = "{{^set}}not set{{/set}} :: {{#set}}set{{/set}}";
|
||||
var string = '{{^set}}not set{{/set}} :: {{#set}}set{{/set}}';
|
||||
|
||||
shouldCompileTo(string, {}, "not set :: ", "inverted sections run when property isn't present in context");
|
||||
shouldCompileTo(string, {set: undefined}, "not set :: ", "inverted sections run when property is undefined");
|
||||
shouldCompileTo(string, {set: false}, "not set :: ", "inverted sections run when property is false");
|
||||
shouldCompileTo(string, {set: true}, " :: set", "inverted sections don't run when property is true");
|
||||
shouldCompileTo(string, {}, 'not set :: ', "inverted sections run when property isn't present in context");
|
||||
shouldCompileTo(string, {set: undefined}, 'not set :: ', 'inverted sections run when property is undefined');
|
||||
shouldCompileTo(string, {set: false}, 'not set :: ', 'inverted sections run when property is false');
|
||||
shouldCompileTo(string, {set: true}, ' :: set', "inverted sections don't run when property is true");
|
||||
});
|
||||
|
||||
it("GH-158: Using array index twice, breaks the template", function() {
|
||||
var string = "{{arr.[0]}}, {{arr.[1]}}";
|
||||
var data = { "arr": [1,2] };
|
||||
it('GH-158: Using array index twice, breaks the template', function() {
|
||||
var string = '{{arr.[0]}}, {{arr.[1]}}';
|
||||
var data = { 'arr': [1, 2] };
|
||||
|
||||
shouldCompileTo(string, data, "1, 2", "it works as expected");
|
||||
shouldCompileTo(string, data, '1, 2', 'it works as expected');
|
||||
});
|
||||
|
||||
it("bug reported by @fat where lambdas weren't being properly resolved", function() {
|
||||
@@ -39,12 +47,12 @@ describe('Regressions', function() {
|
||||
+ '{{/hasThings}}';
|
||||
var data = {
|
||||
thing: function() {
|
||||
return "blah";
|
||||
return 'blah';
|
||||
},
|
||||
things: [
|
||||
{className: "one", word: "@fat"},
|
||||
{className: "two", word: "@dhg"},
|
||||
{className: "three", word:"@sayrer"}
|
||||
{className: 'one', word: '@fat'},
|
||||
{className: 'two', word: '@dhg'},
|
||||
{className: 'three', word: '@sayrer'}
|
||||
],
|
||||
hasThings: function() {
|
||||
return true;
|
||||
@@ -63,14 +71,14 @@ describe('Regressions', function() {
|
||||
|
||||
it('GH-408: Multiple loops fail', function() {
|
||||
var context = [
|
||||
{ name: "John Doe", location: { city: "Chicago" } },
|
||||
{ name: "Jane Doe", location: { city: "New York"} }
|
||||
{ name: 'John Doe', location: { city: 'Chicago' } },
|
||||
{ name: 'Jane Doe', location: { city: 'New York'} }
|
||||
];
|
||||
|
||||
var template = CompilerContext.compile('{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}');
|
||||
|
||||
var result = template(context);
|
||||
equals(result, "John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe", 'It should output multiple times');
|
||||
equals(result, 'John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe', 'It should output multiple times');
|
||||
});
|
||||
|
||||
it('GS-428: Nested if else rendering', function() {
|
||||
@@ -95,11 +103,13 @@ describe('Regressions', function() {
|
||||
});
|
||||
|
||||
it('GH-534: Object prototype aliases', function() {
|
||||
/*eslint-disable no-extend-native */
|
||||
Object.prototype[0xD834] = true;
|
||||
|
||||
shouldCompileTo('{{foo}}', { foo: 'bar' }, 'bar');
|
||||
|
||||
delete Object.prototype[0xD834];
|
||||
/*eslint-enable no-extend-native */
|
||||
});
|
||||
|
||||
it('GH-437: Matching escaping', function() {
|
||||
@@ -111,23 +121,23 @@ describe('Regressions', function() {
|
||||
}, Error);
|
||||
});
|
||||
|
||||
it("GH-676: Using array in escaping mustache fails", function() {
|
||||
var string = "{{arr}}";
|
||||
var data = { "arr": [1,2] };
|
||||
it('GH-676: Using array in escaping mustache fails', function() {
|
||||
var string = '{{arr}}';
|
||||
var data = { 'arr': [1, 2] };
|
||||
|
||||
shouldCompileTo(string, data, data.arr.toString(), "it works as expected");
|
||||
shouldCompileTo(string, data, data.arr.toString(), 'it works as expected');
|
||||
});
|
||||
|
||||
it("Mustache man page", function() {
|
||||
var string = "Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}";
|
||||
it('Mustache man page', function() {
|
||||
var string = 'Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}';
|
||||
var data = {
|
||||
"name": "Chris",
|
||||
"value": 10000,
|
||||
"taxed_value": 10000 - (10000 * 0.4),
|
||||
"in_ca": true
|
||||
'name': 'Chris',
|
||||
'value': 10000,
|
||||
'taxed_value': 10000 - (10000 * 0.4),
|
||||
'in_ca': true
|
||||
};
|
||||
|
||||
shouldCompileTo(string, data, "Hello Chris. You have just won $10000! Well, $6000, after taxes.", "the hello world mustache example works");
|
||||
shouldCompileTo(string, data, 'Hello Chris. You have just won $10000! Well, $6000, after taxes.', 'the hello world mustache example works');
|
||||
});
|
||||
|
||||
it('GH-731: zero context rendering', function() {
|
||||
|
||||
+7
-7
@@ -1,21 +1,21 @@
|
||||
if (typeof(require) !== 'undefined' && require.extensions[".handlebars"]) {
|
||||
if (typeof require !== 'undefined' && require.extensions['.handlebars']) {
|
||||
describe('Require', function() {
|
||||
it('Load .handlebars files with require()', function() {
|
||||
var template = require("./artifacts/example_1");
|
||||
equal(template, require("./artifacts/example_1.handlebars"));
|
||||
var template = require('./artifacts/example_1');
|
||||
equal(template, require('./artifacts/example_1.handlebars'));
|
||||
|
||||
var expected = 'foo\n';
|
||||
var result = template({foo: "foo"});
|
||||
var result = template({foo: 'foo'});
|
||||
|
||||
equal(result, expected);
|
||||
});
|
||||
|
||||
it('Load .hbs files with require()', function() {
|
||||
var template = require("./artifacts/example_2");
|
||||
equal(template, require("./artifacts/example_2.hbs"));
|
||||
var template = require('./artifacts/example_2');
|
||||
equal(template, require('./artifacts/example_2.hbs'));
|
||||
|
||||
var expected = 'Hello, World!\n';
|
||||
var result = template({name: "World"});
|
||||
var result = template({name: 'World'});
|
||||
|
||||
equal(result, expected);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/*globals Handlebars, shouldThrow */
|
||||
|
||||
describe('runtime', function() {
|
||||
describe('#template', function() {
|
||||
it('should throw on invalid templates', function() {
|
||||
|
||||
+5
-6
@@ -1,8 +1,7 @@
|
||||
/*global CompilerContext, Handlebars */
|
||||
try {
|
||||
if (typeof define !== 'function' || !define.amd) {
|
||||
var SourceMap = require('source-map'),
|
||||
SourceMapConsumer = SourceMap.SourceMapConsumer;
|
||||
SourceMapConsumer = SourceMap.SourceMapConsumer;
|
||||
}
|
||||
} catch (err) {
|
||||
/* NOP for in browser */
|
||||
@@ -20,13 +19,13 @@ describe('source-map', function() {
|
||||
equal(!!template.map, !CompilerContext.browser);
|
||||
});
|
||||
it('should map source properly', function() {
|
||||
var source = ' b{{hello}} \n {{bar}}a {{#block arg hash=(subex 1 subval)}}{{/block}}',
|
||||
template = Handlebars.precompile(source, {destName: 'dest.js', srcName: 'src.hbs'});
|
||||
var templateSource = ' b{{hello}} \n {{bar}}a {{#block arg hash=(subex 1 subval)}}{{/block}}',
|
||||
template = Handlebars.precompile(templateSource, {destName: 'dest.js', srcName: 'src.hbs'});
|
||||
|
||||
if (template.map) {
|
||||
var consumer = new SourceMapConsumer(template.map),
|
||||
lines = template.code.split('\n'),
|
||||
srcLines = source.split('\n'),
|
||||
srcLines = templateSource.split('\n'),
|
||||
|
||||
generated = grepLine('" b"', lines),
|
||||
source = grepLine(' b', srcLines);
|
||||
@@ -43,7 +42,7 @@ function grepLine(token, lines) {
|
||||
var column = lines[i].indexOf(token);
|
||||
if (column >= 0) {
|
||||
return {
|
||||
line: i+1,
|
||||
line: i + 1,
|
||||
column: column
|
||||
};
|
||||
}
|
||||
|
||||
+6
-5
@@ -5,12 +5,11 @@ describe('spec', function() {
|
||||
}
|
||||
|
||||
var _ = require('underscore'),
|
||||
Handlebars = require('../lib'),
|
||||
fs = require('fs');
|
||||
|
||||
var specDir =__dirname + '/mustache/specs/';
|
||||
var specDir = __dirname + '/mustache/specs/';
|
||||
var specs = _.filter(fs.readdirSync(specDir), function(name) {
|
||||
return /.*\.json$/.test(name);
|
||||
return (/.*\.json$/).test(name);
|
||||
});
|
||||
|
||||
_.each(specs, function(name) {
|
||||
@@ -26,8 +25,8 @@ describe('spec', function() {
|
||||
// We nest the entire response from partials, not just the literals
|
||||
|| (name === 'partials.json' && test.name === 'Standalone Indentation')
|
||||
|
||||
|| /\{\{\=/.test(test.template)
|
||||
|| _.any(test.partials, function(partial) { return /\{\{\=/.test(partial); })) {
|
||||
|| (/\{\{\=/).test(test.template)
|
||||
|| _.any(test.partials, function(partial) { return (/\{\{\=/).test(partial); })) {
|
||||
it.skip(name + ' - ' + test.name);
|
||||
return;
|
||||
}
|
||||
@@ -35,7 +34,9 @@ describe('spec', function() {
|
||||
var data = _.clone(test.data);
|
||||
if (data.lambda) {
|
||||
// Blergh
|
||||
/*eslint-disable no-eval */
|
||||
data.lambda = eval('(' + data.lambda.js + ')');
|
||||
/*eslint-enable no-eval */
|
||||
}
|
||||
it(name + ' - ' + test.name, function() {
|
||||
if (test.partials) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/*global CompilerContext, Handlebars, shouldThrow */
|
||||
var Exception = Handlebars.Exception;
|
||||
|
||||
describe('strict', function() {
|
||||
|
||||
+44
-45
@@ -1,44 +1,43 @@
|
||||
/*global CompilerContext */
|
||||
describe('string params mode', function() {
|
||||
it("arguments to helpers can be retrieved from options hash in string form", function() {
|
||||
it('arguments to helpers can be retrieved from options hash in string form', function() {
|
||||
var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun) {
|
||||
return "HELP ME MY BOSS " + passiveVoice + ' ' + noun;
|
||||
return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, {helpers: helpers});
|
||||
|
||||
equals(result, "HELP ME MY BOSS is.a slave.driver", "String parameters output");
|
||||
equals(result, 'HELP ME MY BOSS is.a slave.driver', 'String parameters output');
|
||||
});
|
||||
|
||||
it("when using block form, arguments to helpers can be retrieved from options hash in string form", function() {
|
||||
it('when using block form, arguments to helpers can be retrieved from options hash in string form', function() {
|
||||
var template = CompilerContext.compile('{{#wycats is.a slave.driver}}help :({{/wycats}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
return "HELP ME MY BOSS " + passiveVoice + ' ' +
|
||||
return 'HELP ME MY BOSS ' + passiveVoice + ' ' +
|
||||
noun + ': ' + options.fn(this);
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, {helpers: helpers});
|
||||
|
||||
equals(result, "HELP ME MY BOSS is.a slave.driver: help :(", "String parameters output");
|
||||
equals(result, 'HELP ME MY BOSS is.a slave.driver: help :(', 'String parameters output');
|
||||
});
|
||||
|
||||
it("when inside a block in String mode, .. passes the appropriate context in the options hash", function() {
|
||||
it('when inside a block in String mode, .. passes the appropriate context in the options hash', function() {
|
||||
var template = CompilerContext.compile('{{#with dale}}{{tomdale ../need dad.joke}}{{/with}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(desire, noun, options) {
|
||||
return "STOP ME FROM READING HACKER NEWS I " +
|
||||
options.contexts[0][desire] + " " + noun;
|
||||
return 'STOP ME FROM READING HACKER NEWS I ' +
|
||||
options.contexts[0][desire] + ' ' + noun;
|
||||
},
|
||||
|
||||
"with": function(context, options) {
|
||||
'with': function(context, options) {
|
||||
return options.fn(options.contexts[0][context]);
|
||||
}
|
||||
};
|
||||
@@ -49,31 +48,31 @@ describe('string params mode', function() {
|
||||
need: 'need-a'
|
||||
}, {helpers: helpers});
|
||||
|
||||
equals(result, "STOP ME FROM READING HACKER NEWS I need-a dad.joke", "Proper context variable output");
|
||||
equals(result, 'STOP ME FROM READING HACKER NEWS I need-a dad.joke', 'Proper context variable output');
|
||||
});
|
||||
|
||||
it("information about the types is passed along", function() {
|
||||
var template = CompilerContext.compile('{{tomdale "need" dad.joke true false}}', { stringParams: true });
|
||||
it('information about the types is passed along', function() {
|
||||
var template = CompilerContext.compile("{{tomdale 'need' dad.joke true false}}", { stringParams: true });
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(desire, noun, trueBool, falseBool, options) {
|
||||
equal(options.types[0], 'StringLiteral', "the string type is passed");
|
||||
equal(options.types[1], 'PathExpression', "the expression type is passed");
|
||||
equal(options.types[2], 'BooleanLiteral', "the expression type is passed");
|
||||
equal(desire, "need", "the string form is passed for strings");
|
||||
equal(noun, "dad.joke", "the string form is passed for expressions");
|
||||
equal(trueBool, true, "raw booleans are passed through");
|
||||
equal(falseBool, false, "raw booleans are passed through");
|
||||
return "Helper called";
|
||||
equal(options.types[0], 'StringLiteral', 'the string type is passed');
|
||||
equal(options.types[1], 'PathExpression', 'the expression type is passed');
|
||||
equal(options.types[2], 'BooleanLiteral', 'the expression type is passed');
|
||||
equal(desire, 'need', 'the string form is passed for strings');
|
||||
equal(noun, 'dad.joke', 'the string form is passed for expressions');
|
||||
equal(trueBool, true, 'raw booleans are passed through');
|
||||
equal(falseBool, false, 'raw booleans are passed through');
|
||||
return 'Helper called';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers });
|
||||
equal(result, "Helper called");
|
||||
equal(result, 'Helper called');
|
||||
});
|
||||
|
||||
it("hash parameters get type information", function() {
|
||||
var template = CompilerContext.compile('{{tomdale he.says desire="need" noun=dad.joke bool=true}}', { stringParams: true });
|
||||
it('hash parameters get type information', function() {
|
||||
var template = CompilerContext.compile("{{tomdale he.says desire='need' noun=dad.joke bool=true}}", { stringParams: true });
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(exclamation, options) {
|
||||
@@ -94,43 +93,43 @@ describe('string params mode', function() {
|
||||
equal(result, 'Helper called');
|
||||
});
|
||||
|
||||
it("hash parameters get context information", function() {
|
||||
var template = CompilerContext.compile('{{#with dale}}{{tomdale he.says desire="need" noun=../dad/joke bool=true}}{{/with}}', { stringParams: true });
|
||||
it('hash parameters get context information', function() {
|
||||
var template = CompilerContext.compile("{{#with dale}}{{tomdale he.says desire='need' noun=../dad/joke bool=true}}{{/with}}", { stringParams: true });
|
||||
|
||||
var context = {dale: {}};
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(exclamation, options) {
|
||||
equal(exclamation, "he.says");
|
||||
equal(exclamation, 'he.says');
|
||||
equal(options.types[0], 'PathExpression');
|
||||
|
||||
equal(options.contexts.length, 1);
|
||||
equal(options.hashContexts.noun, context);
|
||||
equal(options.hash.desire, "need");
|
||||
equal(options.hash.noun, "dad.joke");
|
||||
equal(options.hash.desire, 'need');
|
||||
equal(options.hash.noun, 'dad.joke');
|
||||
equal(options.hash.bool, true);
|
||||
return "Helper called";
|
||||
return 'Helper called';
|
||||
},
|
||||
"with": function(context, options) {
|
||||
return options.fn(options.contexts[0][context]);
|
||||
'with': function(withContext, options) {
|
||||
return options.fn(options.contexts[0][withContext]);
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(context, { helpers: helpers });
|
||||
equal(result, "Helper called");
|
||||
equal(result, 'Helper called');
|
||||
});
|
||||
|
||||
it("when inside a block in String mode, .. passes the appropriate context in the options hash to a block helper", function() {
|
||||
it('when inside a block in String mode, .. passes the appropriate context in the options hash to a block helper', function() {
|
||||
var template = CompilerContext.compile('{{#with dale}}{{#tomdale ../need dad.joke}}wot{{/tomdale}}{{/with}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(desire, noun, options) {
|
||||
return "STOP ME FROM READING HACKER NEWS I " +
|
||||
options.contexts[0][desire] + " " + noun + " " +
|
||||
return 'STOP ME FROM READING HACKER NEWS I ' +
|
||||
options.contexts[0][desire] + ' ' + noun + ' ' +
|
||||
options.fn(this);
|
||||
},
|
||||
|
||||
"with": function(context, options) {
|
||||
'with': function(context, options) {
|
||||
return options.fn(options.contexts[0][context]);
|
||||
}
|
||||
};
|
||||
@@ -141,23 +140,23 @@ describe('string params mode', function() {
|
||||
need: 'need-a'
|
||||
}, {helpers: helpers});
|
||||
|
||||
equals(result, "STOP ME FROM READING HACKER NEWS I need-a dad.joke wot", "Proper context variable output");
|
||||
equals(result, 'STOP ME FROM READING HACKER NEWS I need-a dad.joke wot', 'Proper context variable output');
|
||||
});
|
||||
|
||||
it("with nested block ambiguous", function() {
|
||||
it('with nested block ambiguous', function() {
|
||||
var template = CompilerContext.compile('{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
'with': function(options) {
|
||||
return "WITH";
|
||||
var helpers = {
|
||||
'with': function() {
|
||||
return 'WITH';
|
||||
},
|
||||
view: function() {
|
||||
return "VIEW";
|
||||
return 'VIEW';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, {helpers: helpers});
|
||||
equals(result, "WITH");
|
||||
equals(result, 'WITH');
|
||||
});
|
||||
|
||||
it('should handle DATA', function() {
|
||||
|
||||
+79
-81
@@ -1,134 +1,133 @@
|
||||
/*global CompilerContext, Handlebars, shouldCompileTo, shouldThrow */
|
||||
describe('subexpressions', function() {
|
||||
it("arg-less helper", function() {
|
||||
var string = "{{foo (bar)}}!";
|
||||
var context = {};
|
||||
var helpers = {
|
||||
it('arg-less helper', function() {
|
||||
var string = '{{foo (bar)}}!';
|
||||
var context = {};
|
||||
var helpers = {
|
||||
foo: function(val) {
|
||||
return val+val;
|
||||
return val + val;
|
||||
},
|
||||
bar: function() {
|
||||
return "LOL";
|
||||
return 'LOL';
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], "LOLLOL!");
|
||||
shouldCompileTo(string, [context, helpers], 'LOLLOL!');
|
||||
});
|
||||
|
||||
it("helper w args", function() {
|
||||
var string = '{{blog (equal a b)}}';
|
||||
it('helper w args', function() {
|
||||
var string = '{{blog (equal a b)}}';
|
||||
|
||||
var context = { bar: "LOL" };
|
||||
var helpers = {
|
||||
var context = { bar: 'LOL' };
|
||||
var helpers = {
|
||||
blog: function(val) {
|
||||
return "val is " + val;
|
||||
return 'val is ' + val;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], "val is true");
|
||||
shouldCompileTo(string, [context, helpers], 'val is true');
|
||||
});
|
||||
|
||||
it("mixed paths and helpers", function() {
|
||||
var string = '{{blog baz.bat (equal a b) baz.bar}}';
|
||||
it('mixed paths and helpers', function() {
|
||||
var string = '{{blog baz.bat (equal a b) baz.bar}}';
|
||||
|
||||
var context = { bar: "LOL", baz: {bat: 'foo!', bar: 'bar!'} };
|
||||
var helpers = {
|
||||
var context = { bar: 'LOL', baz: {bat: 'foo!', bar: 'bar!'} };
|
||||
var helpers = {
|
||||
blog: function(val, that, theOther) {
|
||||
return "val is " + val + ', ' + that + ' and ' + theOther;
|
||||
return 'val is ' + val + ', ' + that + ' and ' + theOther;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], "val is foo!, true and bar!");
|
||||
shouldCompileTo(string, [context, helpers], 'val is foo!, true and bar!');
|
||||
});
|
||||
|
||||
it("supports much nesting", function() {
|
||||
var string = '{{blog (equal (equal true true) true)}}';
|
||||
it('supports much nesting', function() {
|
||||
var string = '{{blog (equal (equal true true) true)}}';
|
||||
|
||||
var context = { bar: "LOL" };
|
||||
var helpers = {
|
||||
var context = { bar: 'LOL' };
|
||||
var helpers = {
|
||||
blog: function(val) {
|
||||
return "val is " + val;
|
||||
return 'val is ' + val;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], "val is true");
|
||||
shouldCompileTo(string, [context, helpers], 'val is true');
|
||||
});
|
||||
|
||||
it('GH-800 : Complex subexpressions', function() {
|
||||
var context = {a: 'a', b:'b', c:{c:'c'}, d:'d', e: {e: 'e'}};
|
||||
var helpers = {
|
||||
var context = {a: 'a', b: 'b', c: {c: 'c'}, d: 'd', e: {e: 'e'}};
|
||||
var helpers = {
|
||||
dash: function(a, b) {
|
||||
return a + "-" + b;
|
||||
return a + '-' + b;
|
||||
},
|
||||
concat: function(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
};
|
||||
|
||||
shouldCompileTo('{{dash "abc" (concat a b)}}', [context, helpers], 'abc-ab');
|
||||
shouldCompileTo("{{dash 'abc' (concat a b)}}", [context, helpers], 'abc-ab');
|
||||
shouldCompileTo('{{dash d (concat a b)}}', [context, helpers], 'd-ab');
|
||||
shouldCompileTo('{{dash c.c (concat a b)}}', [context, helpers], 'c-ab');
|
||||
shouldCompileTo('{{dash (concat a b) c.c}}', [context, helpers], 'ab-c');
|
||||
shouldCompileTo('{{dash (concat a e.e) c.c}}', [context, helpers], 'ae-c');
|
||||
});
|
||||
|
||||
it("provides each nested helper invocation its own options hash", function() {
|
||||
it('provides each nested helper invocation its own options hash', function() {
|
||||
var string = '{{equal (equal true true) true}}';
|
||||
|
||||
var lastOptions = null;
|
||||
var helpers = {
|
||||
var helpers = {
|
||||
equal: function(x, y, options) {
|
||||
if (!options || options === lastOptions) {
|
||||
throw new Error("options hash was reused");
|
||||
throw new Error('options hash was reused');
|
||||
}
|
||||
lastOptions = options;
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [{}, helpers], "true");
|
||||
shouldCompileTo(string, [{}, helpers], 'true');
|
||||
});
|
||||
|
||||
it("with hashes", function() {
|
||||
var string = '{{blog (equal (equal true true) true fun="yes")}}';
|
||||
it('with hashes', function() {
|
||||
var string = "{{blog (equal (equal true true) true fun='yes')}}";
|
||||
|
||||
var context = { bar: "LOL" };
|
||||
var helpers = {
|
||||
var context = { bar: 'LOL' };
|
||||
var helpers = {
|
||||
blog: function(val) {
|
||||
return "val is " + val;
|
||||
return 'val is ' + val;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], "val is true");
|
||||
shouldCompileTo(string, [context, helpers], 'val is true');
|
||||
});
|
||||
|
||||
it("as hashes", function() {
|
||||
var string = '{{blog fun=(equal (blog fun=1) "val is 1")}}';
|
||||
it('as hashes', function() {
|
||||
var string = "{{blog fun=(equal (blog fun=1) 'val is 1')}}";
|
||||
|
||||
var helpers = {
|
||||
var helpers = {
|
||||
blog: function(options) {
|
||||
return "val is " + options.hash.fun;
|
||||
return 'val is ' + options.hash.fun;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [{}, helpers], "val is true");
|
||||
shouldCompileTo(string, [{}, helpers], 'val is true');
|
||||
});
|
||||
|
||||
it("multiple subexpressions in a hash", function() {
|
||||
it('multiple subexpressions in a hash', function() {
|
||||
var string = '{{input aria-label=(t "Name") placeholder=(t "Example User")}}';
|
||||
|
||||
var helpers = {
|
||||
input: function(options) {
|
||||
var hash = options.hash;
|
||||
var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
|
||||
var hash = options.hash;
|
||||
var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
|
||||
var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder);
|
||||
return new Handlebars.SafeString('<input aria-label="' + ariaLabel + '" placeholder="' + placeholder + '" />');
|
||||
},
|
||||
@@ -139,20 +138,20 @@ describe('subexpressions', function() {
|
||||
shouldCompileTo(string, [{}, helpers], '<input aria-label="Name" placeholder="Example User" />');
|
||||
});
|
||||
|
||||
it("multiple subexpressions in a hash with context", function() {
|
||||
it('multiple subexpressions in a hash with context', function() {
|
||||
var string = '{{input aria-label=(t item.field) placeholder=(t item.placeholder)}}';
|
||||
|
||||
var context = {
|
||||
item: {
|
||||
field: "Name",
|
||||
placeholder: "Example User"
|
||||
}
|
||||
field: 'Name',
|
||||
placeholder: 'Example User'
|
||||
}
|
||||
};
|
||||
|
||||
var helpers = {
|
||||
input: function(options) {
|
||||
var hash = options.hash;
|
||||
var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
|
||||
var hash = options.hash;
|
||||
var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
|
||||
var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder);
|
||||
return new Handlebars.SafeString('<input aria-label="' + ariaLabel + '" placeholder="' + placeholder + '" />');
|
||||
},
|
||||
@@ -161,23 +160,23 @@ describe('subexpressions', function() {
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], '<input aria-label="Name" placeholder="Example User" />');
|
||||
});
|
||||
});
|
||||
|
||||
it("in string params mode,", function() {
|
||||
it('in string params mode,', function() {
|
||||
var template = CompilerContext.compile('{{snog (blorg foo x=y) yeah a=b}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
snog: function(a, b, options) {
|
||||
equals(a, 'foo');
|
||||
equals(options.types.length, 2, "string params for outer helper processed correctly");
|
||||
equals(options.types[0], 'SubExpression', "string params for outer helper processed correctly");
|
||||
equals(options.types[1], 'PathExpression', "string params for outer helper processed correctly");
|
||||
equals(options.types.length, 2, 'string params for outer helper processed correctly');
|
||||
equals(options.types[0], 'SubExpression', 'string params for outer helper processed correctly');
|
||||
equals(options.types[1], 'PathExpression', 'string params for outer helper processed correctly');
|
||||
return a + b;
|
||||
},
|
||||
|
||||
blorg: function(a, options) {
|
||||
equals(options.types.length, 1, "string params for inner helper processed correctly");
|
||||
equals(options.types[0], 'PathExpression', "string params for inner helper processed correctly");
|
||||
equals(options.types.length, 1, 'string params for inner helper processed correctly');
|
||||
equals(options.types[0], 'PathExpression', 'string params for inner helper processed correctly');
|
||||
return a;
|
||||
}
|
||||
};
|
||||
@@ -187,54 +186,53 @@ describe('subexpressions', function() {
|
||||
yeah: {}
|
||||
}, {helpers: helpers});
|
||||
|
||||
equals(result, "fooyeah");
|
||||
equals(result, 'fooyeah');
|
||||
});
|
||||
|
||||
it("as hashes in string params mode", function() {
|
||||
|
||||
it('as hashes in string params mode', function() {
|
||||
var template = CompilerContext.compile('{{blog fun=(bork)}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
var helpers = {
|
||||
blog: function(options) {
|
||||
equals(options.hashTypes.fun, 'SubExpression');
|
||||
return "val is " + options.hash.fun;
|
||||
return 'val is ' + options.hash.fun;
|
||||
},
|
||||
bork: function() {
|
||||
return "BORK";
|
||||
return 'BORK';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, {helpers: helpers});
|
||||
equals(result, "val is BORK");
|
||||
equals(result, 'val is BORK');
|
||||
});
|
||||
|
||||
it("subexpression functions on the context", function() {
|
||||
var string = "{{foo (bar)}}!";
|
||||
var context = {
|
||||
it('subexpression functions on the context', function() {
|
||||
var string = '{{foo (bar)}}!';
|
||||
var context = {
|
||||
bar: function() {
|
||||
return "LOL";
|
||||
return 'LOL';
|
||||
}
|
||||
};
|
||||
var helpers = {
|
||||
var helpers = {
|
||||
foo: function(val) {
|
||||
return val+val;
|
||||
return val + val;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], "LOLLOL!");
|
||||
shouldCompileTo(string, [context, helpers], 'LOLLOL!');
|
||||
});
|
||||
|
||||
it("subexpressions can't just be property lookups", function() {
|
||||
var string = "{{foo (bar)}}!";
|
||||
var context = {
|
||||
bar: "LOL"
|
||||
var string = '{{foo (bar)}}!';
|
||||
var context = {
|
||||
bar: 'LOL'
|
||||
};
|
||||
var helpers = {
|
||||
var helpers = {
|
||||
foo: function(val) {
|
||||
return val+val;
|
||||
return val + val;
|
||||
}
|
||||
};
|
||||
shouldThrow(function() {
|
||||
shouldCompileTo(string, [context, helpers], "LOLLOL!");
|
||||
shouldCompileTo(string, [context, helpers], 'LOLLOL!');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+130
-131
@@ -1,4 +1,3 @@
|
||||
/*global Handlebars */
|
||||
function shouldMatchTokens(result, tokens) {
|
||||
for (var index = 0; index < result.length; index++) {
|
||||
equals(result[index].name, tokens[index]);
|
||||
@@ -22,7 +21,7 @@ describe('Tokenizer', function() {
|
||||
var out = [],
|
||||
token;
|
||||
|
||||
while (token = lexer.lex()) {
|
||||
while ((token = lexer.lex())) {
|
||||
var result = parser.terminals_[token] || token;
|
||||
if (!result || result === 'EOF' || result === 'INVALID') {
|
||||
break;
|
||||
@@ -34,292 +33,292 @@ describe('Tokenizer', function() {
|
||||
}
|
||||
|
||||
it('tokenizes a simple mustache as "OPEN ID CLOSE"', function() {
|
||||
var result = tokenize("{{foo}}");
|
||||
var result = tokenize('{{foo}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "ID", "foo");
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('supports unescaping with &', function() {
|
||||
var result = tokenize("{{&bar}}");
|
||||
var result = tokenize('{{&bar}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
|
||||
|
||||
shouldBeToken(result[0], "OPEN", "{{&");
|
||||
shouldBeToken(result[1], "ID", "bar");
|
||||
shouldBeToken(result[0], 'OPEN', '{{&');
|
||||
shouldBeToken(result[1], 'ID', 'bar');
|
||||
});
|
||||
|
||||
it('supports unescaping with {{{', function() {
|
||||
var result = tokenize("{{{bar}}}");
|
||||
var result = tokenize('{{{bar}}}');
|
||||
shouldMatchTokens(result, ['OPEN_UNESCAPED', 'ID', 'CLOSE_UNESCAPED']);
|
||||
|
||||
shouldBeToken(result[1], "ID", "bar");
|
||||
shouldBeToken(result[1], 'ID', 'bar');
|
||||
});
|
||||
|
||||
it('supports escaping delimiters', function() {
|
||||
var result = tokenize("{{foo}} \\{{bar}} {{baz}}");
|
||||
var result = tokenize('{{foo}} \\{{bar}} {{baz}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
||||
|
||||
shouldBeToken(result[3], "CONTENT", " ");
|
||||
shouldBeToken(result[4], "CONTENT", "{{bar}} ");
|
||||
shouldBeToken(result[3], 'CONTENT', ' ');
|
||||
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
||||
});
|
||||
|
||||
it('supports escaping multiple delimiters', function() {
|
||||
var result = tokenize("{{foo}} \\{{bar}} \\{{baz}}");
|
||||
var result = tokenize('{{foo}} \\{{bar}} \\{{baz}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT']);
|
||||
|
||||
shouldBeToken(result[3], "CONTENT", " ");
|
||||
shouldBeToken(result[4], "CONTENT", "{{bar}} ");
|
||||
shouldBeToken(result[5], "CONTENT", "{{baz}}");
|
||||
shouldBeToken(result[3], 'CONTENT', ' ');
|
||||
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
||||
shouldBeToken(result[5], 'CONTENT', '{{baz}}');
|
||||
});
|
||||
|
||||
it('supports escaping a triple stash', function() {
|
||||
var result = tokenize("{{foo}} \\{{{bar}}} {{baz}}");
|
||||
var result = tokenize('{{foo}} \\{{{bar}}} {{baz}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
||||
|
||||
shouldBeToken(result[4], "CONTENT", "{{{bar}}} ");
|
||||
shouldBeToken(result[4], 'CONTENT', '{{{bar}}} ');
|
||||
});
|
||||
|
||||
it('supports escaping escape character', function() {
|
||||
var result = tokenize("{{foo}} \\\\{{bar}} {{baz}}");
|
||||
var result = tokenize('{{foo}} \\\\{{bar}} {{baz}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
||||
|
||||
shouldBeToken(result[3], "CONTENT", " \\");
|
||||
shouldBeToken(result[5], "ID", "bar");
|
||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||
shouldBeToken(result[5], 'ID', 'bar');
|
||||
});
|
||||
|
||||
it('supports escaping multiple escape characters', function() {
|
||||
var result = tokenize("{{foo}} \\\\{{bar}} \\\\{{baz}}");
|
||||
var result = tokenize('{{foo}} \\\\{{bar}} \\\\{{baz}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
||||
|
||||
shouldBeToken(result[3], "CONTENT", " \\");
|
||||
shouldBeToken(result[5], "ID", "bar");
|
||||
shouldBeToken(result[7], "CONTENT", " \\");
|
||||
shouldBeToken(result[9], "ID", "baz");
|
||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||
shouldBeToken(result[5], 'ID', 'bar');
|
||||
shouldBeToken(result[7], 'CONTENT', ' \\');
|
||||
shouldBeToken(result[9], 'ID', 'baz');
|
||||
});
|
||||
|
||||
it('supports escaped mustaches after escaped escape characters', function() {
|
||||
var result = tokenize("{{foo}} \\\\{{bar}} \\{{baz}}");
|
||||
var result = tokenize('{{foo}} \\\\{{bar}} \\{{baz}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT']);
|
||||
|
||||
shouldBeToken(result[3], "CONTENT", " \\");
|
||||
shouldBeToken(result[4], "OPEN", "{{");
|
||||
shouldBeToken(result[5], "ID", "bar");
|
||||
shouldBeToken(result[7], "CONTENT", " ");
|
||||
shouldBeToken(result[8], "CONTENT", "{{baz}}");
|
||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||
shouldBeToken(result[4], 'OPEN', '{{');
|
||||
shouldBeToken(result[5], 'ID', 'bar');
|
||||
shouldBeToken(result[7], 'CONTENT', ' ');
|
||||
shouldBeToken(result[8], 'CONTENT', '{{baz}}');
|
||||
});
|
||||
|
||||
it('supports escaped escape characters after escaped mustaches', function() {
|
||||
var result = tokenize("{{foo}} \\{{bar}} \\\\{{baz}}");
|
||||
var result = tokenize('{{foo}} \\{{bar}} \\\\{{baz}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
||||
|
||||
shouldBeToken(result[4], "CONTENT", "{{bar}} ");
|
||||
shouldBeToken(result[5], "CONTENT", "\\");
|
||||
shouldBeToken(result[6], "OPEN", "{{");
|
||||
shouldBeToken(result[7], "ID", "baz");
|
||||
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
||||
shouldBeToken(result[5], 'CONTENT', '\\');
|
||||
shouldBeToken(result[6], 'OPEN', '{{');
|
||||
shouldBeToken(result[7], 'ID', 'baz');
|
||||
});
|
||||
|
||||
it('supports escaped escape character on a triple stash', function() {
|
||||
var result = tokenize("{{foo}} \\\\{{{bar}}} {{baz}}");
|
||||
var result = tokenize('{{foo}} \\\\{{{bar}}} {{baz}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN_UNESCAPED', 'ID', 'CLOSE_UNESCAPED', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
||||
|
||||
shouldBeToken(result[3], "CONTENT", " \\");
|
||||
shouldBeToken(result[5], "ID", "bar");
|
||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||
shouldBeToken(result[5], 'ID', 'bar');
|
||||
});
|
||||
|
||||
it('tokenizes a simple path', function() {
|
||||
var result = tokenize("{{foo/bar}}");
|
||||
var result = tokenize('{{foo/bar}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('allows dot notation', function() {
|
||||
var result = tokenize("{{foo.bar}}");
|
||||
var result = tokenize('{{foo.bar}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
|
||||
shouldMatchTokens(tokenize("{{foo.bar.baz}}"), ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
shouldMatchTokens(tokenize('{{foo.bar.baz}}'), ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('allows path literals with []', function() {
|
||||
var result = tokenize("{{foo.[bar]}}");
|
||||
var result = tokenize('{{foo.[bar]}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('allows multiple path literals on a line with []', function() {
|
||||
var result = tokenize("{{foo.[bar]}}{{foo.[baz]}}");
|
||||
var result = tokenize('{{foo.[bar]}}{{foo.[baz]}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE', 'OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes {{.}} as OPEN ID CLOSE', function() {
|
||||
var result = tokenize("{{.}}");
|
||||
var result = tokenize('{{.}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes a path as "OPEN (ID SEP)* ID CLOSE"', function() {
|
||||
var result = tokenize("{{../foo/bar}}");
|
||||
var result = tokenize('{{../foo/bar}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "ID", "..");
|
||||
shouldBeToken(result[1], 'ID', '..');
|
||||
});
|
||||
|
||||
it('tokenizes a path with .. as a parent path', function() {
|
||||
var result = tokenize("{{../foo.bar}}");
|
||||
var result = tokenize('{{../foo.bar}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "ID", "..");
|
||||
shouldBeToken(result[1], 'ID', '..');
|
||||
});
|
||||
|
||||
it('tokenizes a path with this/foo as OPEN ID SEP ID CLOSE', function() {
|
||||
var result = tokenize("{{this/foo}}");
|
||||
var result = tokenize('{{this/foo}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "ID", "this");
|
||||
shouldBeToken(result[3], "ID", "foo");
|
||||
shouldBeToken(result[1], 'ID', 'this');
|
||||
shouldBeToken(result[3], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('tokenizes a simple mustache with spaces as "OPEN ID CLOSE"', function() {
|
||||
var result = tokenize("{{ foo }}");
|
||||
var result = tokenize('{{ foo }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "ID", "foo");
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('tokenizes a simple mustache with line breaks as "OPEN ID ID CLOSE"', function() {
|
||||
var result = tokenize("{{ foo \n bar }}");
|
||||
var result = tokenize('{{ foo \n bar }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "ID", "foo");
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('tokenizes raw content as "CONTENT"', function() {
|
||||
var result = tokenize("foo {{ bar }} baz");
|
||||
var result = tokenize('foo {{ bar }} baz');
|
||||
shouldMatchTokens(result, ['CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT']);
|
||||
shouldBeToken(result[0], "CONTENT", "foo ");
|
||||
shouldBeToken(result[4], "CONTENT", " baz");
|
||||
shouldBeToken(result[0], 'CONTENT', 'foo ');
|
||||
shouldBeToken(result[4], 'CONTENT', ' baz');
|
||||
});
|
||||
|
||||
it('tokenizes a partial as "OPEN_PARTIAL ID CLOSE"', function() {
|
||||
var result = tokenize("{{> foo}}");
|
||||
var result = tokenize('{{> foo}}');
|
||||
shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes a partial with context as "OPEN_PARTIAL ID ID CLOSE"', function() {
|
||||
var result = tokenize("{{> foo bar }}");
|
||||
var result = tokenize('{{> foo bar }}');
|
||||
shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes a partial without spaces as "OPEN_PARTIAL ID CLOSE"', function() {
|
||||
var result = tokenize("{{>foo}}");
|
||||
var result = tokenize('{{>foo}}');
|
||||
shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes a partial space at the }); as "OPEN_PARTIAL ID CLOSE"', function() {
|
||||
var result = tokenize("{{>foo }}");
|
||||
var result = tokenize('{{>foo }}');
|
||||
shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes a partial space at the }); as "OPEN_PARTIAL ID CLOSE"', function() {
|
||||
var result = tokenize("{{>foo/bar.baz }}");
|
||||
var result = tokenize('{{>foo/bar.baz }}');
|
||||
shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes a comment as "COMMENT"', function() {
|
||||
var result = tokenize("foo {{! this is a comment }} bar {{ baz }}");
|
||||
var result = tokenize('foo {{! this is a comment }} bar {{ baz }}');
|
||||
shouldMatchTokens(result, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "COMMENT", "{{! this is a comment }}");
|
||||
shouldBeToken(result[1], 'COMMENT', '{{! this is a comment }}');
|
||||
});
|
||||
|
||||
it('tokenizes a block comment as "COMMENT"', function() {
|
||||
var result = tokenize("foo {{!-- this is a {{comment}} --}} bar {{ baz }}");
|
||||
var result = tokenize('foo {{!-- this is a {{comment}} --}} bar {{ baz }}');
|
||||
shouldMatchTokens(result, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "COMMENT", "{{!-- this is a {{comment}} --}}");
|
||||
shouldBeToken(result[1], 'COMMENT', '{{!-- this is a {{comment}} --}}');
|
||||
});
|
||||
|
||||
it('tokenizes a block comment with whitespace as "COMMENT"', function() {
|
||||
var result = tokenize("foo {{!-- this is a\n{{comment}}\n--}} bar {{ baz }}");
|
||||
var result = tokenize('foo {{!-- this is a\n{{comment}}\n--}} bar {{ baz }}');
|
||||
shouldMatchTokens(result, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "COMMENT", "{{!-- this is a\n{{comment}}\n--}}");
|
||||
shouldBeToken(result[1], 'COMMENT', '{{!-- this is a\n{{comment}}\n--}}');
|
||||
});
|
||||
|
||||
it('tokenizes open and closing blocks as OPEN_BLOCK, ID, CLOSE ..., OPEN_ENDBLOCK ID CLOSE', function() {
|
||||
var result = tokenize("{{#foo}}content{{/foo}}");
|
||||
var result = tokenize('{{#foo}}content{{/foo}}');
|
||||
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'CLOSE', 'CONTENT', 'OPEN_ENDBLOCK', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes inverse sections as "INVERSE"', function() {
|
||||
shouldMatchTokens(tokenize("{{^}}"), ['INVERSE']);
|
||||
shouldMatchTokens(tokenize("{{else}}"), ['INVERSE']);
|
||||
shouldMatchTokens(tokenize("{{ else }}"), ['INVERSE']);
|
||||
shouldMatchTokens(tokenize('{{^}}'), ['INVERSE']);
|
||||
shouldMatchTokens(tokenize('{{else}}'), ['INVERSE']);
|
||||
shouldMatchTokens(tokenize('{{ else }}'), ['INVERSE']);
|
||||
});
|
||||
|
||||
it('tokenizes inverse sections with ID as "OPEN_INVERSE ID CLOSE"', function() {
|
||||
var result = tokenize("{{^foo}}");
|
||||
var result = tokenize('{{^foo}}');
|
||||
shouldMatchTokens(result, ['OPEN_INVERSE', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "ID", "foo");
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('tokenizes inverse sections with ID and spaces as "OPEN_INVERSE ID CLOSE"', function() {
|
||||
var result = tokenize("{{^ foo }}");
|
||||
var result = tokenize('{{^ foo }}');
|
||||
shouldMatchTokens(result, ['OPEN_INVERSE', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "ID", "foo");
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('tokenizes mustaches with params as "OPEN ID ID ID CLOSE"', function() {
|
||||
var result = tokenize("{{ foo bar baz }}");
|
||||
var result = tokenize('{{ foo bar baz }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], "ID", "foo");
|
||||
shouldBeToken(result[2], "ID", "bar");
|
||||
shouldBeToken(result[3], "ID", "baz");
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
shouldBeToken(result[2], 'ID', 'bar');
|
||||
shouldBeToken(result[3], 'ID', 'baz');
|
||||
});
|
||||
|
||||
it('tokenizes mustaches with String params as "OPEN ID ID STRING CLOSE"', function() {
|
||||
var result = tokenize("{{ foo bar \"baz\" }}");
|
||||
var result = tokenize('{{ foo bar \'baz\' }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']);
|
||||
shouldBeToken(result[3], "STRING", "baz");
|
||||
shouldBeToken(result[3], 'STRING', 'baz');
|
||||
});
|
||||
|
||||
it('tokenizes mustaches with String params using single quotes as "OPEN ID ID STRING CLOSE"', function() {
|
||||
var result = tokenize("{{ foo bar \'baz\' }}");
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']);
|
||||
shouldBeToken(result[3], "STRING", "baz");
|
||||
shouldBeToken(result[3], 'STRING', 'baz');
|
||||
});
|
||||
|
||||
it('tokenizes String params with spaces inside as "STRING"', function() {
|
||||
var result = tokenize("{{ foo bar \"baz bat\" }}");
|
||||
var result = tokenize('{{ foo bar "baz bat" }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']);
|
||||
shouldBeToken(result[3], "STRING", "baz bat");
|
||||
shouldBeToken(result[3], 'STRING', 'baz bat');
|
||||
});
|
||||
|
||||
it('tokenizes String params with escapes quotes as STRING', function() {
|
||||
var result = tokenize('{{ foo "bar\\"baz" }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'STRING', 'CLOSE']);
|
||||
shouldBeToken(result[2], "STRING", 'bar"baz');
|
||||
shouldBeToken(result[2], 'STRING', 'bar"baz');
|
||||
});
|
||||
|
||||
it('tokenizes String params using single quotes with escapes quotes as STRING', function() {
|
||||
var result = tokenize("{{ foo 'bar\\'baz' }}");
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'STRING', 'CLOSE']);
|
||||
shouldBeToken(result[2], "STRING", "bar'baz");
|
||||
shouldBeToken(result[2], 'STRING', "bar'baz");
|
||||
});
|
||||
|
||||
it('tokenizes numbers', function() {
|
||||
var result = tokenize('{{ foo 1 }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
|
||||
shouldBeToken(result[2], "NUMBER", "1");
|
||||
shouldBeToken(result[2], 'NUMBER', '1');
|
||||
|
||||
result = tokenize('{{ foo 1.1 }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
|
||||
shouldBeToken(result[2], "NUMBER", "1.1");
|
||||
shouldBeToken(result[2], 'NUMBER', '1.1');
|
||||
|
||||
result = tokenize('{{ foo -1 }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
|
||||
shouldBeToken(result[2], "NUMBER", "-1");
|
||||
shouldBeToken(result[2], 'NUMBER', '-1');
|
||||
|
||||
result = tokenize('{{ foo -1.1 }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
|
||||
shouldBeToken(result[2], "NUMBER", "-1.1");
|
||||
shouldBeToken(result[2], 'NUMBER', '-1.1');
|
||||
});
|
||||
|
||||
it('tokenizes booleans', function() {
|
||||
var result = tokenize('{{ foo true }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'BOOLEAN', 'CLOSE']);
|
||||
shouldBeToken(result[2], "BOOLEAN", "true");
|
||||
shouldBeToken(result[2], 'BOOLEAN', 'true');
|
||||
|
||||
result = tokenize('{{ foo false }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'BOOLEAN', 'CLOSE']);
|
||||
shouldBeToken(result[2], "BOOLEAN", "false");
|
||||
shouldBeToken(result[2], 'BOOLEAN', 'false');
|
||||
});
|
||||
|
||||
it('tokenizes undefined and null', function() {
|
||||
@@ -330,77 +329,77 @@ describe('Tokenizer', function() {
|
||||
});
|
||||
|
||||
it('tokenizes hash arguments', function() {
|
||||
var result = tokenize("{{ foo bar=baz }}");
|
||||
var result = tokenize('{{ foo bar=baz }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{ foo bar baz=bat }}");
|
||||
result = tokenize('{{ foo bar baz=bat }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{ foo bar baz=1 }}");
|
||||
result = tokenize('{{ foo bar baz=1 }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'NUMBER', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{ foo bar baz=true }}");
|
||||
result = tokenize('{{ foo bar baz=true }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'BOOLEAN', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{ foo bar baz=false }}");
|
||||
result = tokenize('{{ foo bar baz=false }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'BOOLEAN', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{ foo bar\n baz=bat }}");
|
||||
result = tokenize('{{ foo bar\n baz=bat }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{ foo bar baz=\"bat\" }}");
|
||||
result = tokenize('{{ foo bar baz=\"bat\" }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'STRING', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{ foo bar baz=\"bat\" bam=wot }}");
|
||||
result = tokenize('{{ foo bar baz=\"bat\" bam=wot }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'STRING', 'ID', 'EQUALS', 'ID', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{foo omg bar=baz bat=\"bam\"}}");
|
||||
result = tokenize('{{foo omg bar=baz bat=\"bam\"}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'ID', 'EQUALS', 'STRING', 'CLOSE']);
|
||||
shouldBeToken(result[2], "ID", "omg");
|
||||
shouldBeToken(result[2], 'ID', 'omg');
|
||||
});
|
||||
|
||||
it('tokenizes special @ identifiers', function() {
|
||||
var result = tokenize("{{ @foo }}");
|
||||
var result = tokenize('{{ @foo }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'DATA', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[2], "ID", "foo");
|
||||
shouldBeToken(result[2], 'ID', 'foo');
|
||||
|
||||
result = tokenize("{{ foo @bar }}");
|
||||
result = tokenize('{{ foo @bar }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'DATA', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[3], "ID", "bar");
|
||||
shouldBeToken(result[3], 'ID', 'bar');
|
||||
|
||||
result = tokenize("{{ foo bar=@baz }}");
|
||||
result = tokenize('{{ foo bar=@baz }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'DATA', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[5], "ID", "baz");
|
||||
shouldBeToken(result[5], 'ID', 'baz');
|
||||
});
|
||||
|
||||
it('does not time out in a mustache with a single } followed by EOF', function() {
|
||||
shouldMatchTokens(tokenize("{{foo}"), ['OPEN', 'ID']);
|
||||
shouldMatchTokens(tokenize('{{foo}'), ['OPEN', 'ID']);
|
||||
});
|
||||
|
||||
it('does not time out in a mustache when invalid ID characters are used', function() {
|
||||
shouldMatchTokens(tokenize("{{foo & }}"), ['OPEN', 'ID']);
|
||||
shouldMatchTokens(tokenize('{{foo & }}'), ['OPEN', 'ID']);
|
||||
});
|
||||
|
||||
it('tokenizes subexpressions', function() {
|
||||
var result = tokenize("{{foo (bar)}}");
|
||||
var result = tokenize('{{foo (bar)}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'CLOSE_SEXPR', 'CLOSE']);
|
||||
shouldBeToken(result[1], "ID", "foo");
|
||||
shouldBeToken(result[3], "ID", "bar");
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
shouldBeToken(result[3], 'ID', 'bar');
|
||||
|
||||
result = tokenize("{{foo (a-x b-y)}}");
|
||||
result = tokenize('{{foo (a-x b-y)}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'ID', 'CLOSE_SEXPR', 'CLOSE']);
|
||||
shouldBeToken(result[1], "ID", "foo");
|
||||
shouldBeToken(result[3], "ID", "a-x");
|
||||
shouldBeToken(result[4], "ID", "b-y");
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
shouldBeToken(result[3], 'ID', 'a-x');
|
||||
shouldBeToken(result[4], 'ID', 'b-y');
|
||||
});
|
||||
|
||||
it('tokenizes nested subexpressions', function() {
|
||||
var result = tokenize("{{foo (bar (lol rofl)) (baz)}}");
|
||||
var result = tokenize('{{foo (bar (lol rofl)) (baz)}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'OPEN_SEXPR', 'ID', 'ID', 'CLOSE_SEXPR', 'CLOSE_SEXPR', 'OPEN_SEXPR', 'ID', 'CLOSE_SEXPR', 'CLOSE']);
|
||||
shouldBeToken(result[3], "ID", "bar");
|
||||
shouldBeToken(result[5], "ID", "lol");
|
||||
shouldBeToken(result[6], "ID", "rofl");
|
||||
shouldBeToken(result[10], "ID", "baz");
|
||||
shouldBeToken(result[3], 'ID', 'bar');
|
||||
shouldBeToken(result[5], 'ID', 'lol');
|
||||
shouldBeToken(result[6], 'ID', 'rofl');
|
||||
shouldBeToken(result[10], 'ID', 'baz');
|
||||
});
|
||||
|
||||
it('tokenizes nested subexpressions: literals', function() {
|
||||
@@ -409,19 +408,19 @@ describe('Tokenizer', function() {
|
||||
});
|
||||
|
||||
it('tokenizes block params', function() {
|
||||
var result = tokenize("{{#foo as |bar|}}");
|
||||
var result = tokenize('{{#foo as |bar|}}');
|
||||
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{#foo as |bar baz|}}");
|
||||
result = tokenize('{{#foo as |bar baz|}}');
|
||||
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{#foo as | bar baz |}}");
|
||||
result = tokenize('{{#foo as | bar baz |}}');
|
||||
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{#foo as as | bar baz |}}");
|
||||
result = tokenize('{{#foo as as | bar baz |}}');
|
||||
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
|
||||
|
||||
result = tokenize("{{else foo as |bar baz|}}");
|
||||
result = tokenize('{{else foo as |bar baz|}}');
|
||||
shouldMatchTokens(result, ['OPEN_INVERSE_CHAIN', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
|
||||
});
|
||||
});
|
||||
|
||||
+12
-16
@@ -1,4 +1,3 @@
|
||||
/*global CompilerContext */
|
||||
describe('track ids', function() {
|
||||
var context;
|
||||
beforeEach(function() {
|
||||
@@ -27,7 +26,7 @@ describe('track ids', function() {
|
||||
equal(options.ids[0], 'is.a');
|
||||
equal(options.ids[1], 'slave.driver');
|
||||
|
||||
return "HELP ME MY BOSS " + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -41,7 +40,7 @@ describe('track ids', function() {
|
||||
equal(options.hashIds.bat, 'is.a');
|
||||
equal(options.hashIds.baz, 'slave.driver');
|
||||
|
||||
return "HELP ME MY BOSS " + options.hashIds.bat + ':' + options.hash.bat + ' ' + options.hashIds.baz + ':' + options.hash.baz;
|
||||
return 'HELP ME MY BOSS ' + options.hashIds.bat + ':' + options.hash.bat + ' ' + options.hashIds.baz + ':' + options.hash.baz;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,7 +54,7 @@ describe('track ids', function() {
|
||||
equal(options.ids[0], 'is.a');
|
||||
equal(options.ids[1], '../slave.driver');
|
||||
|
||||
return "HELP ME MY BOSS " + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -69,11 +68,11 @@ describe('track ids', function() {
|
||||
equal(options.ids[0], '@is.a');
|
||||
equal(options.ids[1], '@slave.driver');
|
||||
|
||||
return "HELP ME MY BOSS " + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
equals(template({}, {helpers: helpers, data:context}), 'HELP ME MY BOSS @is.a:foo @slave.driver:bar');
|
||||
equals(template({}, {helpers: helpers, data: context}), 'HELP ME MY BOSS @is.a:foo @slave.driver:bar');
|
||||
});
|
||||
|
||||
it('should return null for constants', function() {
|
||||
@@ -85,7 +84,7 @@ describe('track ids', function() {
|
||||
equal(options.ids[1], null);
|
||||
equal(options.hashIds.key, null);
|
||||
|
||||
return "HELP ME MY BOSS " + passiveVoice + ' ' + noun + ' ' + options.hash.key;
|
||||
return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun + ' ' + options.hash.key;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -99,7 +98,7 @@ describe('track ids', function() {
|
||||
wycats: function(passiveVoice, options) {
|
||||
equal(options.ids[0], true);
|
||||
|
||||
return "HELP ME MY BOSS " + passiveVoice;
|
||||
return 'HELP ME MY BOSS ' + passiveVoice;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -120,7 +119,7 @@ describe('track ids', function() {
|
||||
equal(options.ids[1], 'slave.driver');
|
||||
equal(options.ids[2], 'zomg');
|
||||
|
||||
return "HELP ME MY BOSS " + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -129,6 +128,9 @@ describe('track ids', function() {
|
||||
|
||||
describe('builtin helpers', function() {
|
||||
var helpers = {
|
||||
blockParams: function(name, options) {
|
||||
return name + ':' + options.ids[0] + '\n';
|
||||
},
|
||||
wycats: function(name, options) {
|
||||
return name + ':' + options.data.contextPath + '\n';
|
||||
}
|
||||
@@ -151,13 +153,7 @@ describe('track ids', function() {
|
||||
equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:.array..0\nbar:.array..1\n');
|
||||
});
|
||||
it('should handle block params', function() {
|
||||
var helpers = {
|
||||
wycats: function(name, options) {
|
||||
return name + ':' + options.ids[0] + '\n';
|
||||
}
|
||||
};
|
||||
|
||||
var template = CompilerContext.compile('{{#each array as |value|}}{{wycats value.name}}{{/each}}', {trackIds: true});
|
||||
var template = CompilerContext.compile('{{#each array as |value|}}{{blockParams value.name}}{{/each}}', {trackIds: true});
|
||||
|
||||
equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:array.0.name\nbar:array.1.name\n');
|
||||
});
|
||||
|
||||
+6
-8
@@ -1,19 +1,17 @@
|
||||
/*global Handlebars, shouldCompileTo */
|
||||
|
||||
describe('utils', function() {
|
||||
describe('#SafeString', function() {
|
||||
it("constructing a safestring from a string and checking its type", function() {
|
||||
var safe = new Handlebars.SafeString("testing 1, 2, 3");
|
||||
it('constructing a safestring from a string and checking its type', function() {
|
||||
var safe = new Handlebars.SafeString('testing 1, 2, 3');
|
||||
if (!(safe instanceof Handlebars.SafeString)) {
|
||||
throw new Error('Must be instance of SafeString');
|
||||
}
|
||||
equals(safe == 'testing 1, 2, 3', true, 'SafeString is equivalent to its underlying string');
|
||||
equals(safe.toString(), 'testing 1, 2, 3', 'SafeString is equivalent to its underlying string');
|
||||
});
|
||||
|
||||
it("it should not escape SafeString properties", function() {
|
||||
var name = new Handlebars.SafeString("<em>Sean O'Malley</em>");
|
||||
it('it should not escape SafeString properties', function() {
|
||||
var name = new Handlebars.SafeString('<em>Sean O'Malley</em>');
|
||||
|
||||
shouldCompileTo('{{name}}', [{ name: name }], "<em>Sean O'Malley</em>");
|
||||
shouldCompileTo('{{name}}', [{name: name}], '<em>Sean O'Malley</em>');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/*global Handlebars, shouldThrow */
|
||||
|
||||
describe('Visitor', function() {
|
||||
if (!Handlebars.Visitor || !Handlebars.print) {
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/*global shouldCompileTo, shouldCompileToWithPartials */
|
||||
|
||||
describe('whitespace control', function() {
|
||||
it('should strip whitespace around mustache calls', function() {
|
||||
var hash = {foo: 'bar<'};
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ module.exports = function(grunt) {
|
||||
grunt.log.writeln('Updating to version ' + version);
|
||||
|
||||
async.each([
|
||||
['lib/handlebars/base.js', /var VERSION = "(.*)";/, 'var VERSION = "' + version + '";'],
|
||||
['lib/handlebars/base.js', /var VERSION = ['"](.*)['"];/, 'var VERSION = "' + version + '";'],
|
||||
['components/bower.json', /"version":.*/, '"version": "' + version + '",'],
|
||||
['components/handlebars.js.nuspec', /<version>.*<\/version>/, '<version>' + version + '</version>']
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user