Upgrade prettier to v2

Prettier v2 has the following breaking changes:
* enforces spaces between `function` and params
* enforces trailing commas by default
This commit is contained in:
Jakob Linskeseder
2022-10-19 22:26:53 +02:00
committed by Jay Linski
parent f6ff3bf52b
commit e534a911f3
104 changed files with 1869 additions and 1894 deletions
+5 -5
View File
@@ -1,14 +1,14 @@
module.exports = { module.exports = {
extends: ['eslint:recommended', 'plugin:compat/recommended', 'prettier'], extends: ['eslint:recommended', 'plugin:compat/recommended', 'prettier'],
globals: { globals: {
self: false self: false,
}, },
env: { env: {
node: true, node: true,
es2020: true es2020: true,
}, },
parserOptions: { parserOptions: {
sourceType: 'module' sourceType: 'module',
}, },
rules: { rules: {
'no-console': 'warn', 'no-console': 'warn',
@@ -59,6 +59,6 @@ module.exports = {
// ECMAScript 6 // // ECMAScript 6 //
//--------------// //--------------//
'no-var': 'error' 'no-var': 'error',
} },
}; };
+45 -40
View File
@@ -1,5 +1,5 @@
/* eslint-disable no-process-env */ /* eslint-disable no-process-env */
module.exports = function(grunt) { module.exports = function (grunt) {
grunt.initConfig({ grunt.initConfig({
pkg: grunt.file.readJSON('package.json'), pkg: grunt.file.readJSON('package.json'),
@@ -8,7 +8,7 @@ module.exports = function(grunt) {
copy: { copy: {
dist: { dist: {
options: { options: {
processContent: function(content) { processContent: function (content) {
return ( return (
grunt.template.process( grunt.template.process(
'/**!\n\n @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n*/\n' '/**!\n\n @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n*/\n'
@@ -16,9 +16,9 @@ module.exports = function(grunt) {
content + content +
'\n// @license-end\n' '\n// @license-end\n'
); );
} },
}, },
files: [{ expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/' }] files: [{ expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/' }],
}, },
components: { components: {
files: [ files: [
@@ -26,18 +26,23 @@ module.exports = function(grunt) {
expand: true, expand: true,
cwd: 'components/', cwd: 'components/',
src: ['**'], src: ['**'],
dest: 'dist/components' dest: 'dist/components',
}, },
{ expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/components' } {
] expand: true,
} cwd: 'dist/',
src: ['*.js'],
dest: 'dist/components',
},
],
},
}, },
babel: { babel: {
options: { options: {
sourceMaps: 'inline', sourceMaps: 'inline',
loose: ['es6.modules'], loose: ['es6.modules'],
auxiliaryCommentBefore: 'istanbul ignore next' auxiliaryCommentBefore: 'istanbul ignore next',
}, },
cjs: { cjs: {
files: [ files: [
@@ -45,10 +50,10 @@ module.exports = function(grunt) {
cwd: 'lib/', cwd: 'lib/',
expand: true, expand: true,
src: '**/!(index).js', src: '**/!(index).js',
dest: 'dist/cjs/' dest: 'dist/cjs/',
} },
] ],
} },
}, },
webpack: { webpack: {
options: { options: {
@@ -56,28 +61,28 @@ module.exports = function(grunt) {
output: { output: {
path: 'dist/', path: 'dist/',
library: 'Handlebars', library: 'Handlebars',
libraryTarget: 'umd' libraryTarget: 'umd',
} },
}, },
handlebars: { handlebars: {
entry: './dist/cjs/handlebars.js', entry: './dist/cjs/handlebars.js',
output: { output: {
filename: 'handlebars.js' filename: 'handlebars.js',
} },
}, },
runtime: { runtime: {
entry: './dist/cjs/handlebars.runtime.js', entry: './dist/cjs/handlebars.runtime.js',
output: { output: {
filename: 'handlebars.runtime.js' filename: 'handlebars.runtime.js',
} },
} },
}, },
uglify: { uglify: {
options: { options: {
mangle: true, mangle: true,
compress: true, compress: true,
preserveComments: /(?:^!|@(?:license|preserve|cc_on))/ preserveComments: /(?:^!|@(?:license|preserve|cc_on))/,
}, },
dist: { dist: {
files: [ files: [
@@ -86,19 +91,19 @@ module.exports = function(grunt) {
expand: true, expand: true,
src: ['handlebars*.js', '!*.min.js'], src: ['handlebars*.js', '!*.min.js'],
dest: 'dist/', dest: 'dist/',
rename: function(dest, src) { rename: function (dest, src) {
return dest + src.replace(/\.js$/, '.min.js'); return dest + src.replace(/\.js$/, '.min.js');
} },
} },
] ],
} },
}, },
concat: { concat: {
tests: { tests: {
src: ['spec/!(require).js'], src: ['spec/!(require).js'],
dest: 'tmp/tests.js' dest: 'tmp/tests.js',
} },
}, },
connect: { connect: {
@@ -106,27 +111,27 @@ module.exports = function(grunt) {
options: { options: {
base: '.', base: '.',
hostname: '*', hostname: '*',
port: 9999 port: 9999,
} },
} },
}, },
shell: { shell: {
integrationTests: { integrationTests: {
command: './tests/integration/run-integration-tests.sh' command: './tests/integration/run-integration-tests.sh',
} },
}, },
watch: { watch: {
scripts: { scripts: {
options: { options: {
atBegin: true atBegin: true,
}, },
files: ['src/*', 'lib/**/*.js', 'spec/**/*.js'], files: ['src/*', 'lib/**/*.js', 'spec/**/*.js'],
tasks: ['on-file-change'] tasks: ['on-file-change'],
} },
} },
}); });
// Load tasks from npm // Load tasks from npm
@@ -148,7 +153,7 @@ module.exports = function(grunt) {
'uglify', 'uglify',
'test:min', 'test:min',
'copy:dist', 'copy:dist',
'copy:components' 'copy:components',
]); ]);
// Requires secret properties from .travis.yaml // Requires secret properties from .travis.yaml
@@ -156,7 +161,7 @@ module.exports = function(grunt) {
'default', 'default',
'shell:integrationTests', 'shell:integrationTests',
'metrics', 'metrics',
'publish-to-aws' 'publish-to-aws',
]); ]);
grunt.registerTask('on-file-change', ['build', 'concat:tests', 'test']); grunt.registerTask('on-file-change', ['build', 'concat:tests', 'test']);
@@ -174,6 +179,6 @@ module.exports = function(grunt) {
); );
grunt.registerTask('integration-tests', [ grunt.registerTask('integration-tests', [
'default', 'default',
'shell:integrationTests' 'shell:integrationTests',
]); ]);
}; };
+20 -20
View File
@@ -5,103 +5,103 @@ const yargs = require('yargs')
.option('f', { .option('f', {
type: 'string', type: 'string',
description: 'Output File', description: 'Output File',
alias: 'output' alias: 'output',
}) })
.option('map', { .option('map', {
type: 'string', type: 'string',
description: 'Source Map File' description: 'Source Map File',
}) })
.option('a', { .option('a', {
type: 'boolean', type: 'boolean',
description: 'Exports amd style (require.js)', description: 'Exports amd style (require.js)',
alias: 'amd' alias: 'amd',
}) })
.option('c', { .option('c', {
type: 'string', type: 'string',
description: 'Exports CommonJS style, path to Handlebars module', description: 'Exports CommonJS style, path to Handlebars module',
alias: 'commonjs', alias: 'commonjs',
default: null default: null,
}) })
.option('h', { .option('h', {
type: 'string', type: 'string',
description: 'Path to handlebar.js (only valid for amd-style)', description: 'Path to handlebar.js (only valid for amd-style)',
alias: 'handlebarPath', alias: 'handlebarPath',
default: '' default: '',
}) })
.option('k', { .option('k', {
type: 'string', type: 'string',
description: 'Known helpers', description: 'Known helpers',
alias: 'known' alias: 'known',
}) })
.option('o', { .option('o', {
type: 'boolean', type: 'boolean',
description: 'Known helpers only', description: 'Known helpers only',
alias: 'knownOnly' alias: 'knownOnly',
}) })
.option('m', { .option('m', {
type: 'boolean', type: 'boolean',
description: 'Minimize output', description: 'Minimize output',
alias: 'min' alias: 'min',
}) })
.option('n', { .option('n', {
type: 'string', type: 'string',
description: 'Template namespace', description: 'Template namespace',
alias: 'namespace', alias: 'namespace',
default: 'Handlebars.templates' default: 'Handlebars.templates',
}) })
.option('s', { .option('s', {
type: 'boolean', type: 'boolean',
description: 'Output template function only.', description: 'Output template function only.',
alias: 'simple' alias: 'simple',
}) })
.option('N', { .option('N', {
type: 'string', type: 'string',
description: description:
'Name of passed string templates. Optional if running in a simple mode. Required when operating on multiple templates.', 'Name of passed string templates. Optional if running in a simple mode. Required when operating on multiple templates.',
alias: 'name' alias: 'name',
}) })
.option('i', { .option('i', {
type: 'string', type: 'string',
description: description:
'Generates a template from the passed CLI argument.\n"-" is treated as a special value and causes stdin to be read for the template value.', 'Generates a template from the passed CLI argument.\n"-" is treated as a special value and causes stdin to be read for the template value.',
alias: 'string' alias: 'string',
}) })
.option('r', { .option('r', {
type: 'string', type: 'string',
description: description:
'Template root. Base value that will be stripped from template names.', 'Template root. Base value that will be stripped from template names.',
alias: 'root' alias: 'root',
}) })
.option('p', { .option('p', {
type: 'boolean', type: 'boolean',
description: 'Compiling a partial template', description: 'Compiling a partial template',
alias: 'partial' alias: 'partial',
}) })
.option('d', { .option('d', {
type: 'boolean', type: 'boolean',
description: 'Include data when compiling', description: 'Include data when compiling',
alias: 'data' alias: 'data',
}) })
.option('e', { .option('e', {
type: 'string', type: 'string',
description: 'Template extension.', description: 'Template extension.',
alias: 'extension', alias: 'extension',
default: 'handlebars' default: 'handlebars',
}) })
.option('b', { .option('b', {
type: 'boolean', type: 'boolean',
description: description:
'Removes the BOM (Byte Order Mark) from the beginning of the templates.', 'Removes the BOM (Byte Order Mark) from the beginning of the templates.',
alias: 'bom' alias: 'bom',
}) })
.option('v', { .option('v', {
type: 'boolean', type: 'boolean',
description: 'Prints the current compiler version', description: 'Prints the current compiler version',
alias: 'version' alias: 'version',
}) })
.option('help', { .option('help', {
type: 'boolean', type: 'boolean',
description: 'Outputs this message' description: 'Outputs this message',
}) })
.wrap(120); .wrap(120);
@@ -110,7 +110,7 @@ argv.files = argv._;
delete argv._; delete argv._;
const Precompiler = require('../dist/cjs/precompiler'); const Precompiler = require('../dist/cjs/precompiler');
Precompiler.loadTemplates(argv, function(err, opts) { Precompiler.loadTemplates(argv, function (err, opts) {
if (err) { if (err) {
throw err; throw err;
} }
+2 -2
View File
@@ -2,6 +2,6 @@
module.exports = { module.exports = {
env: { env: {
// Handlebars should run natively in the browser // Handlebars should run natively in the browser
node: false node: false,
} },
}; };
+3 -3
View File
@@ -2,7 +2,7 @@ import {
parser as Parser, parser as Parser,
parse, parse,
parseWithoutProcessing, parseWithoutProcessing,
Visitor Visitor,
} from '@handlebars/parser'; } from '@handlebars/parser';
import runtime from './handlebars.runtime'; import runtime from './handlebars.runtime';
@@ -18,10 +18,10 @@ let _create = runtime.create;
function create() { function create() {
let hb = _create(); let hb = _create();
hb.compile = function(input, options) { hb.compile = function (input, options) {
return compile(input, options, hb); return compile(input, options, hb);
}; };
hb.precompile = function(input, options) { hb.precompile = function (input, options) {
return precompile(input, options, hb); return precompile(input, options, hb);
}; };
+1 -1
View File
@@ -20,7 +20,7 @@ function create() {
hb.escapeExpression = Utils.escapeExpression; hb.escapeExpression = Utils.escapeExpression;
hb.VM = runtime; hb.VM = runtime;
hb.template = function(spec) { hb.template = function (spec) {
return runtime.template(spec, hb); return runtime.template(spec, hb);
}; };
+8 -8
View File
@@ -17,7 +17,7 @@ export const REVISION_CHANGES = {
5: '== 2.0.0-alpha.x', 5: '== 2.0.0-alpha.x',
6: '>= 2.0.0-beta.1', 6: '>= 2.0.0-beta.1',
7: '>= 4.0.0 <4.3.0', 7: '>= 4.0.0 <4.3.0',
8: '>= 4.3.0' 8: '>= 4.3.0',
}; };
const objectType = '[object Object]'; const objectType = '[object Object]';
@@ -37,7 +37,7 @@ HandlebarsEnvironment.prototype = {
logger: logger, logger: logger,
log: logger.log, log: logger.log,
registerHelper: function(name, fn) { registerHelper: function (name, fn) {
if (toString.call(name) === objectType) { if (toString.call(name) === objectType) {
if (fn) { if (fn) {
throw new Exception('Arg not supported with multiple helpers'); throw new Exception('Arg not supported with multiple helpers');
@@ -47,11 +47,11 @@ HandlebarsEnvironment.prototype = {
this.helpers[name] = fn; this.helpers[name] = fn;
} }
}, },
unregisterHelper: function(name) { unregisterHelper: function (name) {
delete this.helpers[name]; delete this.helpers[name];
}, },
registerPartial: function(name, partial) { registerPartial: function (name, partial) {
if (toString.call(name) === objectType) { if (toString.call(name) === objectType) {
extend(this.partials, name); extend(this.partials, name);
} else { } else {
@@ -63,11 +63,11 @@ HandlebarsEnvironment.prototype = {
this.partials[name] = partial; this.partials[name] = partial;
} }
}, },
unregisterPartial: function(name) { unregisterPartial: function (name) {
delete this.partials[name]; delete this.partials[name];
}, },
registerDecorator: function(name, fn) { registerDecorator: function (name, fn) {
if (toString.call(name) === objectType) { if (toString.call(name) === objectType) {
if (fn) { if (fn) {
throw new Exception('Arg not supported with multiple decorators'); throw new Exception('Arg not supported with multiple decorators');
@@ -77,7 +77,7 @@ HandlebarsEnvironment.prototype = {
this.decorators[name] = fn; this.decorators[name] = fn;
} }
}, },
unregisterDecorator: function(name) { unregisterDecorator: function (name) {
delete this.decorators[name]; delete this.decorators[name];
}, },
/** /**
@@ -86,7 +86,7 @@ HandlebarsEnvironment.prototype = {
*/ */
resetLoggedPropertyAccesses() { resetLoggedPropertyAccesses() {
resetLoggedProperties(); resetLoggedProperties();
} },
}; };
export let log = logger.log; export let log = logger.log;
+5 -5
View File
@@ -4,7 +4,7 @@ let AST = {
// a mustache is definitely a helper if: // a mustache is definitely a helper if:
// * it is an eligible helper, and // * it is an eligible helper, and
// * it has at least one parameter or hash segment // * it has at least one parameter or hash segment
helperExpression: function(node) { helperExpression: function (node) {
return ( return (
node.type === 'SubExpression' || node.type === 'SubExpression' ||
((node.type === 'MustacheStatement' || ((node.type === 'MustacheStatement' ||
@@ -13,18 +13,18 @@ let AST = {
); );
}, },
scopedId: function(path) { scopedId: function (path) {
return /^\.|this\b/.test(path.original); return /^\.|this\b/.test(path.original);
}, },
// an ID is simple if it only has one part, and that part is not // an ID is simple if it only has one part, and that part is not
// `..` or `this`. // `..` or `this`.
simpleId: function(path) { simpleId: function (path) {
return ( return (
path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth
); );
} },
} },
}; };
// Must be exported as an object rather than the root of the module as the jison lexer // Must be exported as an object rather than the root of the module as the jison lexer
+20 -20
View File
@@ -17,7 +17,7 @@ try {
/* istanbul ignore if: tested but not covered in istanbul due to dist build */ /* istanbul ignore if: tested but not covered in istanbul due to dist build */
if (!SourceNode) { if (!SourceNode) {
SourceNode = function(line, column, srcFile, chunks) { SourceNode = function (line, column, srcFile, chunks) {
this.src = ''; this.src = '';
if (chunks) { if (chunks) {
this.add(chunks); this.add(chunks);
@@ -25,24 +25,24 @@ if (!SourceNode) {
}; };
/* istanbul ignore next */ /* istanbul ignore next */
SourceNode.prototype = { SourceNode.prototype = {
add: function(chunks) { add: function (chunks) {
if (isArray(chunks)) { if (isArray(chunks)) {
chunks = chunks.join(''); chunks = chunks.join('');
} }
this.src += chunks; this.src += chunks;
}, },
prepend: function(chunks) { prepend: function (chunks) {
if (isArray(chunks)) { if (isArray(chunks)) {
chunks = chunks.join(''); chunks = chunks.join('');
} }
this.src = chunks + this.src; this.src = chunks + this.src;
}, },
toStringWithSourceMap: function() { toStringWithSourceMap: function () {
return { code: this.toString() }; return { code: this.toString() };
}, },
toString: function() { toString: function () {
return this.src; return this.src;
} },
}; };
} }
@@ -70,32 +70,32 @@ CodeGen.prototype = {
isEmpty() { isEmpty() {
return !this.source.length; return !this.source.length;
}, },
prepend: function(source, loc) { prepend: function (source, loc) {
this.source.unshift(this.wrap(source, loc)); this.source.unshift(this.wrap(source, loc));
}, },
push: function(source, loc) { push: function (source, loc) {
this.source.push(this.wrap(source, loc)); this.source.push(this.wrap(source, loc));
}, },
merge: function() { merge: function () {
let source = this.empty(); let source = this.empty();
this.each(function(line) { this.each(function (line) {
source.add([' ', line, '\n']); source.add([' ', line, '\n']);
}); });
return source; return source;
}, },
each: function(iter) { each: function (iter) {
for (let i = 0, len = this.source.length; i < len; i++) { for (let i = 0, len = this.source.length; i < len; i++) {
iter(this.source[i]); iter(this.source[i]);
} }
}, },
empty: function() { empty: function () {
let loc = this.currentLocation || { start: {} }; let loc = this.currentLocation || { start: {} };
return new SourceNode(loc.start.line, loc.start.column, this.srcFile); return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
}, },
wrap: function(chunk, loc = this.currentLocation || { start: {} }) { wrap: function (chunk, loc = this.currentLocation || { start: {} }) {
if (chunk instanceof SourceNode) { if (chunk instanceof SourceNode) {
return chunk; return chunk;
} }
@@ -110,12 +110,12 @@ CodeGen.prototype = {
); );
}, },
functionCall: function(fn, type, params) { functionCall: function (fn, type, params) {
params = this.generateList(params); params = this.generateList(params);
return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']); return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']);
}, },
quotedString: function(str) { quotedString: function (str) {
return ( return (
'"' + '"' +
(str + '') (str + '')
@@ -129,10 +129,10 @@ CodeGen.prototype = {
); );
}, },
objectLiteral: function(obj) { objectLiteral: function (obj) {
let pairs = []; let pairs = [];
Object.keys(obj).forEach(key => { Object.keys(obj).forEach((key) => {
let value = castChunk(obj[key], this); let value = castChunk(obj[key], this);
if (value !== 'undefined') { if (value !== 'undefined') {
pairs.push([this.quotedString(key), ':', value]); pairs.push([this.quotedString(key), ':', value]);
@@ -145,7 +145,7 @@ CodeGen.prototype = {
return ret; return ret;
}, },
generateList: function(entries) { generateList: function (entries) {
let ret = this.empty(); let ret = this.empty();
for (let i = 0, len = entries.length; i < len; i++) { for (let i = 0, len = entries.length; i < len; i++) {
@@ -159,13 +159,13 @@ CodeGen.prototype = {
return ret; return ret;
}, },
generateArray: function(entries) { generateArray: function (entries) {
let ret = this.generateList(entries); let ret = this.generateList(entries);
ret.prepend('['); ret.prepend('[');
ret.add(']'); ret.add(']');
return ret; return ret;
} },
}; };
export default CodeGen; export default CodeGen;
+34 -34
View File
@@ -16,7 +16,7 @@ export function Compiler() {}
Compiler.prototype = { Compiler.prototype = {
compiler: Compiler, compiler: Compiler,
equals: function(other) { equals: function (other) {
let len = this.opcodes.length; let len = this.opcodes.length;
if (other.opcodes.length !== len) { if (other.opcodes.length !== len) {
return false; return false;
@@ -47,7 +47,7 @@ Compiler.prototype = {
guid: 0, guid: 0,
compile: function(program, options) { compile: function (program, options) {
this.sourceNode = []; this.sourceNode = [];
this.opcodes = []; this.opcodes = [];
this.children = []; this.children = [];
@@ -65,7 +65,7 @@ Compiler.prototype = {
unless: true, unless: true,
with: true, with: true,
log: true, log: true,
lookup: true lookup: true,
}, },
options.knownHelpers options.knownHelpers
); );
@@ -73,7 +73,7 @@ Compiler.prototype = {
return this.accept(program); return this.accept(program);
}, },
compileProgram: function(program) { compileProgram: function (program) {
let childCompiler = new this.compiler(), // eslint-disable-line new-cap let childCompiler = new this.compiler(), // eslint-disable-line new-cap
result = childCompiler.compile(program, this.options), result = childCompiler.compile(program, this.options),
guid = this.guid++; guid = this.guid++;
@@ -86,7 +86,7 @@ Compiler.prototype = {
return guid; return guid;
}, },
accept: function(node) { accept: function (node) {
/* istanbul ignore next: Sanity code */ /* istanbul ignore next: Sanity code */
if (!this[node.type]) { if (!this[node.type]) {
throw new Exception('Unknown type: ' + node.type, node); throw new Exception('Unknown type: ' + node.type, node);
@@ -98,7 +98,7 @@ Compiler.prototype = {
return ret; return ret;
}, },
Program: function(program) { Program: function (program) {
this.options.blockParams.unshift(program.blockParams); this.options.blockParams.unshift(program.blockParams);
let body = program.body, let body = program.body,
@@ -115,7 +115,7 @@ Compiler.prototype = {
return this; return this;
}, },
BlockStatement: function(block) { BlockStatement: function (block) {
transformLiteralToPath(block); transformLiteralToPath(block);
let program = block.program, let program = block.program,
@@ -160,7 +160,7 @@ Compiler.prototype = {
this.opcode('registerDecorator', params.length, path.original); this.opcode('registerDecorator', params.length, path.original);
}, },
PartialStatement: function(partial) { PartialStatement: function (partial) {
this.usePartial = true; this.usePartial = true;
let program = partial.program; let program = partial.program;
@@ -199,11 +199,11 @@ Compiler.prototype = {
this.opcode('invokePartial', isDynamic, partialName, indent); this.opcode('invokePartial', isDynamic, partialName, indent);
this.opcode('append'); this.opcode('append');
}, },
PartialBlockStatement: function(partialBlock) { PartialBlockStatement: function (partialBlock) {
this.PartialStatement(partialBlock); this.PartialStatement(partialBlock);
}, },
MustacheStatement: function(mustache) { MustacheStatement: function (mustache) {
this.SubExpression(mustache); this.SubExpression(mustache);
if (mustache.escaped && !this.options.noEscape) { if (mustache.escaped && !this.options.noEscape) {
@@ -216,15 +216,15 @@ Compiler.prototype = {
this.DecoratorBlock(decorator); this.DecoratorBlock(decorator);
}, },
ContentStatement: function(content) { ContentStatement: function (content) {
if (content.value) { if (content.value) {
this.opcode('appendContent', content.value); this.opcode('appendContent', content.value);
} }
}, },
CommentStatement: function() {}, CommentStatement: function () {},
SubExpression: function(sexpr) { SubExpression: function (sexpr) {
transformLiteralToPath(sexpr); transformLiteralToPath(sexpr);
let type = this.classifySexpr(sexpr); let type = this.classifySexpr(sexpr);
@@ -236,7 +236,7 @@ Compiler.prototype = {
this.ambiguousSexpr(sexpr); this.ambiguousSexpr(sexpr);
} }
}, },
ambiguousSexpr: function(sexpr, program, inverse) { ambiguousSexpr: function (sexpr, program, inverse) {
let path = sexpr.path, let path = sexpr.path,
name = path.parts[0], name = path.parts[0],
isBlock = program != null || inverse != null; isBlock = program != null || inverse != null;
@@ -252,14 +252,14 @@ Compiler.prototype = {
this.opcode('invokeAmbiguous', name, isBlock); this.opcode('invokeAmbiguous', name, isBlock);
}, },
simpleSexpr: function(sexpr) { simpleSexpr: function (sexpr) {
let path = sexpr.path; let path = sexpr.path;
path.strict = true; path.strict = true;
this.accept(path); this.accept(path);
this.opcode('resolvePossibleLambda'); this.opcode('resolvePossibleLambda');
}, },
helperSexpr: function(sexpr, program, inverse) { helperSexpr: function (sexpr, program, inverse) {
let params = this.setupFullMustacheParams(sexpr, program, inverse), let params = this.setupFullMustacheParams(sexpr, program, inverse),
path = sexpr.path, path = sexpr.path,
name = path.parts[0]; name = path.parts[0];
@@ -285,7 +285,7 @@ Compiler.prototype = {
} }
}, },
PathExpression: function(path) { PathExpression: function (path) {
this.addDepth(path.depth); this.addDepth(path.depth);
this.opcode('getContext', path.depth); this.opcode('getContext', path.depth);
@@ -312,27 +312,27 @@ Compiler.prototype = {
} }
}, },
StringLiteral: function(string) { StringLiteral: function (string) {
this.opcode('pushString', string.value); this.opcode('pushString', string.value);
}, },
NumberLiteral: function(number) { NumberLiteral: function (number) {
this.opcode('pushLiteral', number.value); this.opcode('pushLiteral', number.value);
}, },
BooleanLiteral: function(bool) { BooleanLiteral: function (bool) {
this.opcode('pushLiteral', bool.value); this.opcode('pushLiteral', bool.value);
}, },
UndefinedLiteral: function() { UndefinedLiteral: function () {
this.opcode('pushLiteral', 'undefined'); this.opcode('pushLiteral', 'undefined');
}, },
NullLiteral: function() { NullLiteral: function () {
this.opcode('pushLiteral', 'null'); this.opcode('pushLiteral', 'null');
}, },
Hash: function(hash) { Hash: function (hash) {
let pairs = hash.pairs, let pairs = hash.pairs,
i = 0, i = 0,
l = pairs.length; l = pairs.length;
@@ -349,15 +349,15 @@ Compiler.prototype = {
}, },
// HELPERS // HELPERS
opcode: function(name) { opcode: function (name) {
this.opcodes.push({ this.opcodes.push({
opcode: name, opcode: name,
args: slice.call(arguments, 1), args: slice.call(arguments, 1),
loc: this.sourceNode[0].loc loc: this.sourceNode[0].loc,
}); });
}, },
addDepth: function(depth) { addDepth: function (depth) {
if (!depth) { if (!depth) {
return; return;
} }
@@ -365,7 +365,7 @@ Compiler.prototype = {
this.useDepths = true; this.useDepths = true;
}, },
classifySexpr: function(sexpr) { classifySexpr: function (sexpr) {
let isSimple = AST.helpers.simpleId(sexpr.path); let isSimple = AST.helpers.simpleId(sexpr.path);
let isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]); let isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]);
@@ -400,17 +400,17 @@ Compiler.prototype = {
} }
}, },
pushParams: function(params) { pushParams: function (params) {
for (let i = 0, l = params.length; i < l; i++) { for (let i = 0, l = params.length; i < l; i++) {
this.pushParam(params[i]); this.pushParam(params[i]);
} }
}, },
pushParam: function(val) { pushParam: function (val) {
this.accept(val); this.accept(val);
}, },
setupFullMustacheParams: function(sexpr, program, inverse, omitEmpty) { setupFullMustacheParams: function (sexpr, program, inverse, omitEmpty) {
let params = sexpr.params; let params = sexpr.params;
this.pushParams(params); this.pushParams(params);
@@ -426,7 +426,7 @@ Compiler.prototype = {
return params; return params;
}, },
blockParamIndex: function(name) { blockParamIndex: function (name) {
for ( for (
let depth = 0, len = this.options.blockParams.length; let depth = 0, len = this.options.blockParams.length;
depth < len; depth < len;
@@ -438,7 +438,7 @@ Compiler.prototype = {
return [depth, param]; return [depth, param];
} }
} }
} },
}; };
export function precompile(input, options = {}, env) { export function precompile(input, options = {}, env) {
@@ -467,7 +467,7 @@ export function compile(input, options = {}, env) {
} }
// Template is only compiled on first use and cached after that point. // Template is only compiled on first use and cached after that point.
return function(context, execOptions) { return function (context, execOptions) {
if (!compiled) { if (!compiled) {
compiled = compileInput(); compiled = compileInput();
} }
@@ -530,7 +530,7 @@ function transformLiteralToPath(sexpr) {
depth: 0, depth: 0,
parts: [literal.original + ''], parts: [literal.original + ''],
original: literal.original + '', original: literal.original + '',
loc: literal.loc loc: literal.loc,
}; };
} }
} }
+80 -80
View File
@@ -12,25 +12,25 @@ function JavaScriptCompiler() {}
JavaScriptCompiler.prototype = { JavaScriptCompiler.prototype = {
// PUBLIC API: You can override these methods in a subclass to provide // PUBLIC API: You can override these methods in a subclass to provide
// alternative compiled forms for name lookup and buffering semantics // alternative compiled forms for name lookup and buffering semantics
nameLookup: function(parent, name /*, type */) { nameLookup: function (parent, name /*, type */) {
return this.internalNameLookup(parent, name); return this.internalNameLookup(parent, name);
}, },
depthedLookup: function(name) { depthedLookup: function (name) {
return [ return [
this.aliasable('container.lookup'), this.aliasable('container.lookup'),
'(depths, ', '(depths, ',
JSON.stringify(name), JSON.stringify(name),
')' ')',
]; ];
}, },
compilerInfo: function() { compilerInfo: function () {
const revision = COMPILER_REVISION, const revision = COMPILER_REVISION,
versions = REVISION_CHANGES[revision]; versions = REVISION_CHANGES[revision];
return [revision, versions]; return [revision, versions];
}, },
appendToBuffer: function(source, location, explicit) { appendToBuffer: function (source, location, explicit) {
// Force a source as this simplifies the merge logic. // Force a source as this simplifies the merge logic.
if (!isArray(source)) { if (!isArray(source)) {
source = [source]; source = [source];
@@ -50,18 +50,18 @@ JavaScriptCompiler.prototype = {
} }
}, },
initializeBuffer: function() { initializeBuffer: function () {
return this.quotedString(''); return this.quotedString('');
}, },
// END PUBLIC API // END PUBLIC API
internalNameLookup: function(parent, name) { internalNameLookup: function (parent, name) {
this.lookupPropertyFunctionIsUsed = true; this.lookupPropertyFunctionIsUsed = true;
return ['lookupProperty(', parent, ',', JSON.stringify(name), ')']; return ['lookupProperty(', parent, ',', JSON.stringify(name), ')'];
}, },
lookupPropertyFunctionIsUsed: false, lookupPropertyFunctionIsUsed: false,
compile: function(environment, options, context, asObject) { compile: function (environment, options, context, asObject) {
this.environment = environment; this.environment = environment;
this.options = options; this.options = options;
this.precompile = !asObject; this.precompile = !asObject;
@@ -71,7 +71,7 @@ JavaScriptCompiler.prototype = {
this.context = context || { this.context = context || {
decorators: [], decorators: [],
programs: [], programs: [],
environments: [] environments: [],
}; };
this.preamble(); this.preamble();
@@ -123,7 +123,7 @@ JavaScriptCompiler.prototype = {
this.decorators.prepend([ this.decorators.prepend([
'var decorators = container.decorators, ', 'var decorators = container.decorators, ',
this.lookupPropertyFunctionVarDeclaration(), this.lookupPropertyFunctionVarDeclaration(),
';\n' ';\n',
]); ]);
this.decorators.push('return fn;'); this.decorators.push('return fn;');
@@ -137,7 +137,7 @@ JavaScriptCompiler.prototype = {
'data', 'data',
'blockParams', 'blockParams',
'depths', 'depths',
this.decorators.merge() this.decorators.merge(),
]); ]);
} else { } else {
this.decorators.prepend( this.decorators.prepend(
@@ -154,7 +154,7 @@ JavaScriptCompiler.prototype = {
if (!this.isChild) { if (!this.isChild) {
let ret = { let ret = {
compiler: this.compilerInfo(), compiler: this.compilerInfo(),
main: fn main: fn,
}; };
if (this.decorators) { if (this.decorators) {
@@ -211,7 +211,7 @@ JavaScriptCompiler.prototype = {
} }
}, },
preamble: function() { preamble: function () {
// track the last context pushed into place to allow skipping the // track the last context pushed into place to allow skipping the
// getContext opcode when it would be a noop // getContext opcode when it would be a noop
this.lastContext = 0; this.lastContext = 0;
@@ -219,7 +219,7 @@ JavaScriptCompiler.prototype = {
this.decorators = new CodeGen(this.options.srcName); this.decorators = new CodeGen(this.options.srcName);
}, },
createFunctionContext: function(asObject) { createFunctionContext: function (asObject) {
let varDeclarations = ''; let varDeclarations = '';
let locals = this.stackVars.concat(this.registers.list); let locals = this.stackVars.concat(this.registers.list);
@@ -234,7 +234,7 @@ JavaScriptCompiler.prototype = {
// aliases will not be used, but this case is already being run on the client and // 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. // we aren't concern about minimizing the template size.
let aliasCount = 0; let aliasCount = 0;
Object.keys(this.aliases).forEach(alias => { Object.keys(this.aliases).forEach((alias) => {
let node = this.aliases[alias]; let node = this.aliases[alias];
if (node.children && node.referenceCount > 1) { if (node.children && node.referenceCount > 1) {
varDeclarations += ', alias' + ++aliasCount + '=' + alias; varDeclarations += ', alias' + ++aliasCount + '=' + alias;
@@ -268,18 +268,18 @@ JavaScriptCompiler.prototype = {
params.join(','), params.join(','),
') {\n ', ') {\n ',
source, source,
'}' '}',
]); ]);
} }
}, },
mergeSource: function(varDeclarations) { mergeSource: function (varDeclarations) {
let isSimple = this.environment.isSimple, let isSimple = this.environment.isSimple,
appendOnly = !this.forceBuffer, appendOnly = !this.forceBuffer,
appendFirst, appendFirst,
sourceSeen, sourceSeen,
bufferStart, bufferStart,
bufferEnd; bufferEnd;
this.source.each(line => { this.source.each((line) => {
if (line.appendToBuffer) { if (line.appendToBuffer) {
if (bufferStart) { if (bufferStart) {
line.prepend(' + '); line.prepend(' + ');
@@ -333,7 +333,7 @@ JavaScriptCompiler.prototype = {
return this.source.merge(); return this.source.merge();
}, },
lookupPropertyFunctionVarDeclaration: function() { lookupPropertyFunctionVarDeclaration: function () {
return ` return `
lookupProperty = container.lookupProperty || function(parent, propertyName) { lookupProperty = container.lookupProperty || function(parent, propertyName) {
if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {
@@ -353,7 +353,7 @@ JavaScriptCompiler.prototype = {
// `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and
// replace it on the stack with the result of properly // replace it on the stack with the result of properly
// invoking blockHelperMissing. // invoking blockHelperMissing.
blockValue: function(name) { blockValue: function (name) {
let blockHelperMissing = this.aliasable( let blockHelperMissing = this.aliasable(
'container.hooks.blockHelperMissing' 'container.hooks.blockHelperMissing'
), ),
@@ -372,7 +372,7 @@ JavaScriptCompiler.prototype = {
// Compiler value, before: lastHelper=value of last found helper, if any // Compiler value, before: lastHelper=value of last found helper, if any
// On stack, after, if no lastHelper: same as [blockValue] // On stack, after, if no lastHelper: same as [blockValue]
// On stack, after, if lastHelper: value // On stack, after, if lastHelper: value
ambiguousBlockValue: function() { ambiguousBlockValue: function () {
// We're being a bit cheeky and reusing the options value from the prior exec // We're being a bit cheeky and reusing the options value from the prior exec
let blockHelperMissing = this.aliasable( let blockHelperMissing = this.aliasable(
'container.hooks.blockHelperMissing' 'container.hooks.blockHelperMissing'
@@ -392,7 +392,7 @@ JavaScriptCompiler.prototype = {
current, current,
' = ', ' = ',
this.source.functionCall(blockHelperMissing, 'call', params), this.source.functionCall(blockHelperMissing, 'call', params),
'}' '}',
]); ]);
}, },
@@ -402,7 +402,7 @@ JavaScriptCompiler.prototype = {
// On stack, after: ... // On stack, after: ...
// //
// Appends the string value of `content` to the current buffer // Appends the string value of `content` to the current buffer
appendContent: function(content) { appendContent: function (content) {
if (this.pendingContent) { if (this.pendingContent) {
content = this.pendingContent + content; content = this.pendingContent + content;
} else { } else {
@@ -421,9 +421,9 @@ JavaScriptCompiler.prototype = {
// //
// If `value` is truthy, or 0, it is coerced into a string and appended // If `value` is truthy, or 0, it is coerced into a string and appended
// Otherwise, the empty string is appended // Otherwise, the empty string is appended
append: function() { append: function () {
if (this.isInline()) { if (this.isInline()) {
this.replaceStack(current => [' != null ? ', current, ' : ""']); this.replaceStack((current) => [' != null ? ', current, ' : ""']);
this.pushSource(this.appendToBuffer(this.popStack())); this.pushSource(this.appendToBuffer(this.popStack()));
} else { } else {
@@ -433,13 +433,13 @@ JavaScriptCompiler.prototype = {
local, local,
' != null) { ', ' != null) { ',
this.appendToBuffer(local, undefined, true), this.appendToBuffer(local, undefined, true),
' }' ' }',
]); ]);
if (this.environment.isSimple) { if (this.environment.isSimple) {
this.pushSource([ this.pushSource([
'else { ', 'else { ',
this.appendToBuffer("''", undefined, true), this.appendToBuffer("''", undefined, true),
' }' ' }',
]); ]);
} }
} }
@@ -451,13 +451,13 @@ JavaScriptCompiler.prototype = {
// On stack, after: ... // On stack, after: ...
// //
// Escape `value` and append it to the buffer // Escape `value` and append it to the buffer
appendEscaped: function() { appendEscaped: function () {
this.pushSource( this.pushSource(
this.appendToBuffer([ this.appendToBuffer([
this.aliasable('container.escapeExpression'), this.aliasable('container.escapeExpression'),
'(', '(',
this.popStack(), this.popStack(),
')' ')',
]) ])
); );
}, },
@@ -469,7 +469,7 @@ JavaScriptCompiler.prototype = {
// Compiler value, after: lastContext=depth // Compiler value, after: lastContext=depth
// //
// Set the value of the `lastContext` compiler value to the depth // Set the value of the `lastContext` compiler value to the depth
getContext: function(depth) { getContext: function (depth) {
this.lastContext = depth; this.lastContext = depth;
}, },
@@ -479,7 +479,7 @@ JavaScriptCompiler.prototype = {
// On stack, after: currentContext, ... // On stack, after: currentContext, ...
// //
// Pushes the value of the current context onto the stack. // Pushes the value of the current context onto the stack.
pushContext: function() { pushContext: function () {
this.pushStackLiteral(this.contextName(this.lastContext)); this.pushStackLiteral(this.contextName(this.lastContext));
}, },
@@ -490,7 +490,7 @@ JavaScriptCompiler.prototype = {
// //
// Looks up the value of `name` on the current context and pushes // Looks up the value of `name` on the current context and pushes
// it onto the stack. // it onto the stack.
lookupOnContext: function(parts, falsy, strict, scoped) { lookupOnContext: function (parts, falsy, strict, scoped) {
let i = 0; let i = 0;
if (!scoped && this.options.compat && !this.lastContext) { if (!scoped && this.options.compat && !this.lastContext) {
@@ -511,7 +511,7 @@ JavaScriptCompiler.prototype = {
// //
// Looks up the value of `parts` on the given block param and pushes // Looks up the value of `parts` on the given block param and pushes
// it onto the stack. // it onto the stack.
lookupBlockParam: function(blockParamId, parts) { lookupBlockParam: function (blockParamId, parts) {
this.useBlockParams = true; this.useBlockParams = true;
this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']); this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']);
@@ -524,7 +524,7 @@ JavaScriptCompiler.prototype = {
// On stack, after: data, ... // On stack, after: data, ...
// //
// Push the data lookup operator // Push the data lookup operator
lookupData: function(depth, parts, strict) { lookupData: function (depth, parts, strict) {
if (!depth) { if (!depth) {
this.pushStackLiteral('data'); this.pushStackLiteral('data');
} else { } else {
@@ -534,7 +534,7 @@ JavaScriptCompiler.prototype = {
this.resolvePath('data', parts, 0, true, strict); this.resolvePath('data', parts, 0, true, strict);
}, },
resolvePath: function(type, parts, i, falsy, strict) { resolvePath: function (type, parts, i, falsy, strict) {
if (this.options.strict || this.options.assumeObjects) { if (this.options.strict || this.options.assumeObjects) {
this.push( this.push(
strictLookup(this.options.strict && strict, this, parts, i, type) strictLookup(this.options.strict && strict, this, parts, i, type)
@@ -545,7 +545,7 @@ JavaScriptCompiler.prototype = {
let len = parts.length; let len = parts.length;
for (; i < len; i++) { for (; i < len; i++) {
/* eslint-disable no-loop-func */ /* eslint-disable no-loop-func */
this.replaceStack(current => { this.replaceStack((current) => {
let lookup = this.nameLookup(current, parts[i], type); let lookup = this.nameLookup(current, parts[i], type);
// We want to ensure that zero and false are handled properly if the context (falsy flag) // We want to ensure that zero and false are handled properly if the context (falsy flag)
// needs to have the special handling for these values. // needs to have the special handling for these values.
@@ -567,27 +567,27 @@ JavaScriptCompiler.prototype = {
// //
// If the `value` is a lambda, replace it on the stack by // If the `value` is a lambda, replace it on the stack by
// the return value of the lambda // the return value of the lambda
resolvePossibleLambda: function() { resolvePossibleLambda: function () {
this.push([ this.push([
this.aliasable('container.lambda'), this.aliasable('container.lambda'),
'(', '(',
this.popStack(), this.popStack(),
', ', ', ',
this.contextName(0), this.contextName(0),
')' ')',
]); ]);
}, },
emptyHash: function(omitEmpty) { emptyHash: function (omitEmpty) {
this.pushStackLiteral(omitEmpty ? 'undefined' : '{}'); this.pushStackLiteral(omitEmpty ? 'undefined' : '{}');
}, },
pushHash: function() { pushHash: function () {
if (this.hash) { if (this.hash) {
this.hashes.push(this.hash); this.hashes.push(this.hash);
} }
this.hash = { values: {} }; this.hash = { values: {} };
}, },
popHash: function() { popHash: function () {
let hash = this.hash; let hash = this.hash;
this.hash = this.hashes.pop(); this.hash = this.hashes.pop();
@@ -600,7 +600,7 @@ JavaScriptCompiler.prototype = {
// On stack, after: quotedString(string), ... // On stack, after: quotedString(string), ...
// //
// Push a quoted version of `string` onto the stack // Push a quoted version of `string` onto the stack
pushString: function(string) { pushString: function (string) {
this.pushStackLiteral(this.quotedString(string)); this.pushStackLiteral(this.quotedString(string));
}, },
@@ -612,7 +612,7 @@ JavaScriptCompiler.prototype = {
// Pushes a value onto the stack. This operation prevents // Pushes a value onto the stack. This operation prevents
// the compiler from creating a temporary variable to hold // the compiler from creating a temporary variable to hold
// it. // it.
pushLiteral: function(value) { pushLiteral: function (value) {
this.pushStackLiteral(value); this.pushStackLiteral(value);
}, },
@@ -624,7 +624,7 @@ JavaScriptCompiler.prototype = {
// Push a program expression onto the stack. This takes // Push a program expression onto the stack. This takes
// a compile-time guid and converts it into a runtime-accessible // a compile-time guid and converts it into a runtime-accessible
// expression. // expression.
pushProgram: function(guid) { pushProgram: function (guid) {
if (guid != null) { if (guid != null) {
this.pushStackLiteral(this.programExpression(guid)); this.pushStackLiteral(this.programExpression(guid));
} else { } else {
@@ -649,9 +649,9 @@ JavaScriptCompiler.prototype = {
'fn', 'fn',
'props', 'props',
'container', 'container',
options options,
]), ]),
' || fn;' ' || fn;',
]); ]);
}, },
@@ -664,7 +664,7 @@ JavaScriptCompiler.prototype = {
// and pushes the helper's return value onto the stack. // and pushes the helper's return value onto the stack.
// //
// If the helper is not found, `helperMissing` is called. // If the helper is not found, `helperMissing` is called.
invokeHelper: function(paramSize, name, isSimple) { invokeHelper: function (paramSize, name, isSimple) {
let nonHelper = this.popStack(), let nonHelper = this.popStack(),
helper = this.setupHelper(paramSize, name); helper = this.setupHelper(paramSize, name);
@@ -685,7 +685,7 @@ JavaScriptCompiler.prototype = {
let functionLookupCode = [ let functionLookupCode = [
'(', '(',
this.itemsSeparatedBy(possibleFunctionCalls, '||'), this.itemsSeparatedBy(possibleFunctionCalls, '||'),
')' ')',
]; ];
let functionCall = this.source.functionCall( let functionCall = this.source.functionCall(
functionLookupCode, functionLookupCode,
@@ -695,7 +695,7 @@ JavaScriptCompiler.prototype = {
this.push(functionCall); this.push(functionCall);
}, },
itemsSeparatedBy: function(items, separator) { itemsSeparatedBy: function (items, separator) {
let result = []; let result = [];
result.push(items[0]); result.push(items[0]);
for (let i = 1; i < items.length; i++) { for (let i = 1; i < items.length; i++) {
@@ -710,7 +710,7 @@ JavaScriptCompiler.prototype = {
// //
// This operation is used when the helper is known to exist, // This operation is used when the helper is known to exist,
// so a `helperMissing` fallback is not required. // so a `helperMissing` fallback is not required.
invokeKnownHelper: function(paramSize, name) { invokeKnownHelper: function (paramSize, name) {
let helper = this.setupHelper(paramSize, name); let helper = this.setupHelper(paramSize, name);
this.push(this.source.functionCall(helper.name, 'call', helper.callParams)); this.push(this.source.functionCall(helper.name, 'call', helper.callParams));
}, },
@@ -727,7 +727,7 @@ JavaScriptCompiler.prototype = {
// This operation emits more code than the other options, // This operation emits more code than the other options,
// and can be avoided by passing the `knownHelpers` and // and can be avoided by passing the `knownHelpers` and
// `knownHelpersOnly` flags at compile-time. // `knownHelpersOnly` flags at compile-time.
invokeAmbiguous: function(name, helperCall) { invokeAmbiguous: function (name, helperCall) {
this.useRegister('helper'); this.useRegister('helper');
let nonHelper = this.popStack(); let nonHelper = this.popStack();
@@ -759,7 +759,7 @@ JavaScriptCompiler.prototype = {
this.aliasable('"function"'), this.aliasable('"function"'),
' ? ', ' ? ',
this.source.functionCall('helper', 'call', helper.callParams), this.source.functionCall('helper', 'call', helper.callParams),
' : helper))' ' : helper))',
]); ]);
}, },
@@ -770,7 +770,7 @@ JavaScriptCompiler.prototype = {
// //
// This operation pops off a context, invokes a partial with that context, // This operation pops off a context, invokes a partial with that context,
// and pushes the result of the invocation back. // and pushes the result of the invocation back.
invokePartial: function(isDynamic, name, indent) { invokePartial: function (isDynamic, name, indent) {
let params = [], let params = [],
options = this.setupParams(name, 1, params); options = this.setupParams(name, 1, params);
@@ -807,7 +807,7 @@ JavaScriptCompiler.prototype = {
// On stack, after: ..., hash, ... // On stack, after: ..., hash, ...
// //
// Pops a value off the stack and assigns it to the current hash // Pops a value off the stack and assigns it to the current hash
assignToHash: function(key) { assignToHash: function (key) {
this.hash.values[key] = this.popStack(); this.hash.values[key] = this.popStack();
}, },
@@ -815,7 +815,7 @@ JavaScriptCompiler.prototype = {
compiler: JavaScriptCompiler, compiler: JavaScriptCompiler,
compileChildren: function(environment, options) { compileChildren: function (environment, options) {
let children = environment.children, let children = environment.children,
child, child,
compiler; compiler;
@@ -853,7 +853,7 @@ JavaScriptCompiler.prototype = {
} }
} }
}, },
matchExistingProgram: function(child) { matchExistingProgram: function (child) {
for (let i = 0, len = this.context.environments.length; i < len; i++) { for (let i = 0, len = this.context.environments.length; i < len; i++) {
let environment = this.context.environments[i]; let environment = this.context.environments[i];
if (environment && environment.equals(child)) { if (environment && environment.equals(child)) {
@@ -862,7 +862,7 @@ JavaScriptCompiler.prototype = {
} }
}, },
programExpression: function(guid) { programExpression: function (guid) {
let child = this.environment.children[guid], let child = this.environment.children[guid],
programParams = [child.index, 'data', child.blockParams]; programParams = [child.index, 'data', child.blockParams];
@@ -876,14 +876,14 @@ JavaScriptCompiler.prototype = {
return 'container.program(' + programParams.join(', ') + ')'; return 'container.program(' + programParams.join(', ') + ')';
}, },
useRegister: function(name) { useRegister: function (name) {
if (!this.registers[name]) { if (!this.registers[name]) {
this.registers[name] = true; this.registers[name] = true;
this.registers.list.push(name); this.registers.list.push(name);
} }
}, },
push: function(expr) { push: function (expr) {
if (!(expr instanceof Literal)) { if (!(expr instanceof Literal)) {
expr = this.source.wrap(expr); expr = this.source.wrap(expr);
} }
@@ -892,11 +892,11 @@ JavaScriptCompiler.prototype = {
return expr; return expr;
}, },
pushStackLiteral: function(item) { pushStackLiteral: function (item) {
this.push(new Literal(item)); this.push(new Literal(item));
}, },
pushSource: function(source) { pushSource: function (source) {
if (this.pendingContent) { if (this.pendingContent) {
this.source.push( this.source.push(
this.appendToBuffer( this.appendToBuffer(
@@ -912,7 +912,7 @@ JavaScriptCompiler.prototype = {
} }
}, },
replaceStack: function(callback) { replaceStack: function (callback) {
let prefix = ['('], let prefix = ['('],
stack, stack,
createdStack, createdStack,
@@ -951,17 +951,17 @@ JavaScriptCompiler.prototype = {
this.push(prefix.concat(item, ')')); this.push(prefix.concat(item, ')'));
}, },
incrStack: function() { incrStack: function () {
this.stackSlot++; this.stackSlot++;
if (this.stackSlot > this.stackVars.length) { if (this.stackSlot > this.stackVars.length) {
this.stackVars.push('stack' + this.stackSlot); this.stackVars.push('stack' + this.stackSlot);
} }
return this.topStackName(); return this.topStackName();
}, },
topStackName: function() { topStackName: function () {
return 'stack' + this.stackSlot; return 'stack' + this.stackSlot;
}, },
flushInline: function() { flushInline: function () {
let inlineStack = this.inlineStack; let inlineStack = this.inlineStack;
this.inlineStack = []; this.inlineStack = [];
for (let i = 0, len = inlineStack.length; i < len; i++) { for (let i = 0, len = inlineStack.length; i < len; i++) {
@@ -976,11 +976,11 @@ JavaScriptCompiler.prototype = {
} }
} }
}, },
isInline: function() { isInline: function () {
return this.inlineStack.length; return this.inlineStack.length;
}, },
popStack: function(wrapped) { popStack: function (wrapped) {
let inline = this.isInline(), let inline = this.isInline(),
item = (inline ? this.inlineStack : this.compileStack).pop(); item = (inline ? this.inlineStack : this.compileStack).pop();
@@ -998,7 +998,7 @@ JavaScriptCompiler.prototype = {
} }
}, },
topStack: function() { topStack: function () {
let stack = this.isInline() ? this.inlineStack : this.compileStack, let stack = this.isInline() ? this.inlineStack : this.compileStack,
item = stack[stack.length - 1]; item = stack[stack.length - 1];
@@ -1010,7 +1010,7 @@ JavaScriptCompiler.prototype = {
} }
}, },
contextName: function(context) { contextName: function (context) {
if (this.useDepths && context) { if (this.useDepths && context) {
return 'depths[' + context + ']'; return 'depths[' + context + ']';
} else { } else {
@@ -1018,15 +1018,15 @@ JavaScriptCompiler.prototype = {
} }
}, },
quotedString: function(str) { quotedString: function (str) {
return this.source.quotedString(str); return this.source.quotedString(str);
}, },
objectLiteral: function(obj) { objectLiteral: function (obj) {
return this.source.objectLiteral(obj); return this.source.objectLiteral(obj);
}, },
aliasable: function(name) { aliasable: function (name) {
let ret = this.aliases[name]; let ret = this.aliases[name];
if (ret) { if (ret) {
ret.referenceCount++; ret.referenceCount++;
@@ -1040,7 +1040,7 @@ JavaScriptCompiler.prototype = {
return ret; return ret;
}, },
setupHelper: function(paramSize, name, blockHelper) { setupHelper: function (paramSize, name, blockHelper) {
let params = [], let params = [],
paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper); paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);
let foundHelper = this.nameLookup('helpers', name, 'helper'), let foundHelper = this.nameLookup('helpers', name, 'helper'),
@@ -1054,11 +1054,11 @@ JavaScriptCompiler.prototype = {
params: params, params: params,
paramsInit: paramsInit, paramsInit: paramsInit,
name: foundHelper, name: foundHelper,
callParams: [callContext].concat(params) callParams: [callContext].concat(params),
}; };
}, },
setupParams: function(helper, paramSize, params) { setupParams: function (helper, paramSize, params) {
let options = {}, let options = {},
objectArgs = !params, objectArgs = !params,
param; param;
@@ -1101,7 +1101,7 @@ JavaScriptCompiler.prototype = {
return options; return options;
}, },
setupHelperArgs: function(helper, paramSize, params, useRegister) { setupHelperArgs: function (helper, paramSize, params, useRegister) {
let options = this.setupParams(helper, paramSize, params); let options = this.setupParams(helper, paramSize, params);
options.loc = JSON.stringify(this.source.currentLocation); options.loc = JSON.stringify(this.source.currentLocation);
options = this.objectLiteral(options); options = this.objectLiteral(options);
@@ -1115,10 +1115,10 @@ JavaScriptCompiler.prototype = {
} else { } else {
return options; return options;
} }
} },
}; };
(function() { (function () {
const reservedWords = ( const reservedWords = (
'break else new var' + 'break else new var' +
' case finally return void' + ' case finally return void' +
@@ -1148,7 +1148,7 @@ JavaScriptCompiler.prototype = {
/** /**
* @deprecated May be removed in the next major version * @deprecated May be removed in the next major version
*/ */
JavaScriptCompiler.isValidJavaScriptVariableName = function(name) { JavaScriptCompiler.isValidJavaScriptVariableName = function (name) {
return ( return (
!JavaScriptCompiler.RESERVED_WORDS[name] && !JavaScriptCompiler.RESERVED_WORDS[name] &&
/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name) /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)
@@ -1175,7 +1175,7 @@ function strictLookup(requireTerminal, compiler, parts, i, type) {
compiler.quotedString(parts[i]), compiler.quotedString(parts[i]),
', ', ', ',
JSON.stringify(compiler.source.currentLocation), JSON.stringify(compiler.source.currentLocation),
' )' ' )',
]; ];
} else { } else {
return stack; return stack;
+21 -18
View File
@@ -1,22 +1,25 @@
import { extend } from '../utils'; import { extend } from '../utils';
export default function(instance) { export default function (instance) {
instance.registerDecorator('inline', function(fn, props, container, options) { instance.registerDecorator(
let ret = fn; 'inline',
if (!props.partials) { function (fn, props, container, options) {
props.partials = {}; let ret = fn;
ret = function(context, options) { if (!props.partials) {
// Create a new partials stack frame prior to exec. props.partials = {};
let original = container.partials; ret = function (context, options) {
container.partials = extend({}, original, props.partials); // Create a new partials stack frame prior to exec.
let ret = fn(context, options); let original = container.partials;
container.partials = original; container.partials = extend({}, original, props.partials);
return ret; let ret = fn(context, options);
}; container.partials = original;
return ret;
};
}
props.partials[options.args[0]] = options.fn;
return ret;
} }
);
props.partials[options.args[0]] = options.fn;
return ret;
});
} }
@@ -1,7 +1,7 @@
import { isArray } from '../utils'; import { isArray } from '../utils';
export default function(instance) { export default function (instance) {
instance.registerHelper('blockHelperMissing', function(context, options) { instance.registerHelper('blockHelperMissing', function (context, options) {
let inverse = options.inverse, let inverse = options.inverse,
fn = options.fn; fn = options.fn;
+4 -4
View File
@@ -1,8 +1,8 @@
import { Exception } from '@handlebars/parser'; import { Exception } from '@handlebars/parser';
import { createFrame, isArray, isFunction } from '../utils'; import { createFrame, isArray, isFunction } from '../utils';
export default function(instance) { export default function (instance) {
instance.registerHelper('each', function(context, options) { instance.registerHelper('each', function (context, options) {
if (!options) { if (!options) {
throw new Exception('Must pass iterator to #each'); throw new Exception('Must pass iterator to #each');
} }
@@ -33,7 +33,7 @@ export default function(instance) {
ret + ret +
fn(context[field], { fn(context[field], {
data: data, data: data,
blockParams: [context[field], field] blockParams: [context[field], field],
}); });
} }
@@ -57,7 +57,7 @@ export default function(instance) {
} else { } else {
let priorKey; let priorKey;
Object.keys(context).forEach(key => { Object.keys(context).forEach((key) => {
// We're running the iterations one step out of sync so we can detect // 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 // the last iteration without have to scan the object twice and create
// an intermediate keys array. // an intermediate keys array.
+2 -2
View File
@@ -1,7 +1,7 @@
import { Exception } from '@handlebars/parser'; import { Exception } from '@handlebars/parser';
export default function(instance) { export default function (instance) {
instance.registerHelper('helperMissing', function(/* [args, ]options */) { instance.registerHelper('helperMissing', function (/* [args, ]options */) {
if (arguments.length === 1) { if (arguments.length === 1) {
// A missing field in a {{foo}} construct. // A missing field in a {{foo}} construct.
return undefined; return undefined;
+4 -4
View File
@@ -1,8 +1,8 @@
import { Exception } from '@handlebars/parser'; import { Exception } from '@handlebars/parser';
import { isEmpty, isFunction } from '../utils'; import { isEmpty, isFunction } from '../utils';
export default function(instance) { export default function (instance) {
instance.registerHelper('if', function(conditional, options) { instance.registerHelper('if', function (conditional, options) {
if (arguments.length != 2) { if (arguments.length != 2) {
throw new Exception('#if requires exactly one argument'); throw new Exception('#if requires exactly one argument');
} }
@@ -20,14 +20,14 @@ export default function(instance) {
} }
}); });
instance.registerHelper('unless', function(conditional, options) { instance.registerHelper('unless', function (conditional, options) {
if (arguments.length != 2) { if (arguments.length != 2) {
throw new Exception('#unless requires exactly one argument'); throw new Exception('#unless requires exactly one argument');
} }
return instance.helpers['if'].call(this, conditional, { return instance.helpers['if'].call(this, conditional, {
fn: options.inverse, fn: options.inverse,
inverse: options.fn, inverse: options.fn,
hash: options.hash hash: options.hash,
}); });
}); });
} }
+2 -2
View File
@@ -1,5 +1,5 @@
export default function(instance) { export default function (instance) {
instance.registerHelper('log', function(/* message, options */) { instance.registerHelper('log', function (/* message, options */) {
let args = [undefined], let args = [undefined],
options = arguments[arguments.length - 1]; options = arguments[arguments.length - 1];
for (let i = 0; i < arguments.length - 1; i++) { for (let i = 0; i < arguments.length - 1; i++) {
+2 -2
View File
@@ -1,5 +1,5 @@
export default function(instance) { export default function (instance) {
instance.registerHelper('lookup', function(obj, field, options) { instance.registerHelper('lookup', function (obj, field, options) {
if (!obj) { if (!obj) {
// Note for 5.0: Change to "obj == null" in 5.0 // Note for 5.0: Change to "obj == null" in 5.0
return obj; return obj;
+3 -3
View File
@@ -1,8 +1,8 @@
import { Exception } from '@handlebars/parser'; import { Exception } from '@handlebars/parser';
import { isEmpty, isFunction } from '../utils'; import { isEmpty, isFunction } from '../utils';
export default function(instance) { export default function (instance) {
instance.registerHelper('with', function(context, options) { instance.registerHelper('with', function (context, options) {
if (arguments.length != 2) { if (arguments.length != 2) {
throw new Exception('#with requires exactly one argument'); throw new Exception('#with requires exactly one argument');
} }
@@ -17,7 +17,7 @@ export default function(instance) {
return fn(context, { return fn(context, {
data: data, data: data,
blockParams: [context] blockParams: [context],
}); });
} else { } else {
return options.inverse(this); return options.inverse(this);
+4 -4
View File
@@ -20,15 +20,15 @@ export function createProtoAccessControl(runtimeOptions) {
defaultPropertyWhiteList, defaultPropertyWhiteList,
runtimeOptions.allowedProtoProperties runtimeOptions.allowedProtoProperties
), ),
defaultValue: runtimeOptions.allowProtoPropertiesByDefault defaultValue: runtimeOptions.allowProtoPropertiesByDefault,
}, },
methods: { methods: {
whitelist: createNewLookupObject( whitelist: createNewLookupObject(
defaultMethodWhiteList, defaultMethodWhiteList,
runtimeOptions.allowedProtoMethods runtimeOptions.allowedProtoMethods
), ),
defaultValue: runtimeOptions.allowProtoMethodsByDefault defaultValue: runtimeOptions.allowProtoMethodsByDefault,
} },
}; };
} }
@@ -64,7 +64,7 @@ function logUnexpectedPropertyAccessOnce(propertyName) {
} }
export function resetLoggedProperties() { export function resetLoggedProperties() {
Object.keys(loggedProperties).forEach(propertyName => { Object.keys(loggedProperties).forEach((propertyName) => {
delete loggedProperties[propertyName]; delete loggedProperties[propertyName];
}); });
} }
+1 -1
View File
@@ -4,7 +4,7 @@ export function wrapHelper(helper, transformOptionsFn) {
// We try to make the wrapper least-invasive by not wrapping it, if the helper is not a function. // We try to make the wrapper least-invasive by not wrapping it, if the helper is not a function.
return helper; return helper;
} }
let wrapper = function(/* dynamic arguments */) { let wrapper = function (/* dynamic arguments */) {
const options = arguments[arguments.length - 1]; const options = arguments[arguments.length - 1];
arguments[arguments.length - 1] = transformOptionsFn(options); arguments[arguments.length - 1] = transformOptionsFn(options);
return helper.apply(this, arguments); return helper.apply(this, arguments);
+3 -3
View File
@@ -5,7 +5,7 @@ let logger = {
level: 'info', level: 'info',
// Maps a given level value to the `methodMap` indexes above. // Maps a given level value to the `methodMap` indexes above.
lookupLevel: function(level) { lookupLevel: function (level) {
if (typeof level === 'string') { if (typeof level === 'string') {
let levelMap = indexOf(logger.methodMap, level.toLowerCase()); let levelMap = indexOf(logger.methodMap, level.toLowerCase());
if (levelMap >= 0) { if (levelMap >= 0) {
@@ -19,7 +19,7 @@ let logger = {
}, },
// Can be overridden in the host environment // Can be overridden in the host environment
log: function(level, ...message) { log: function (level, ...message) {
level = logger.lookupLevel(level); level = logger.lookupLevel(level);
if ( if (
@@ -33,7 +33,7 @@ let logger = {
} }
console[method](...message); // eslint-disable-line no-console console[method](...message); // eslint-disable-line no-console
} }
} },
}; };
export default logger; export default logger;
+2 -2
View File
@@ -1,9 +1,9 @@
export default function(Handlebars) { export default function (Handlebars) {
/* istanbul ignore next */ /* istanbul ignore next */
let root = typeof global !== 'undefined' ? global : window, // eslint-disable-line no-undef let root = typeof global !== 'undefined' ? global : window, // eslint-disable-line no-undef
$Handlebars = root.Handlebars; $Handlebars = root.Handlebars;
/* istanbul ignore next */ /* istanbul ignore next */
Handlebars.noConflict = function() { Handlebars.noConflict = function () {
if (root.Handlebars === Handlebars) { if (root.Handlebars === Handlebars) {
root.Handlebars = $Handlebars; root.Handlebars = $Handlebars;
} }
+15 -15
View File
@@ -4,13 +4,13 @@ import {
COMPILER_REVISION, COMPILER_REVISION,
createFrame, createFrame,
LAST_COMPATIBLE_COMPILER_REVISION, LAST_COMPATIBLE_COMPILER_REVISION,
REVISION_CHANGES REVISION_CHANGES,
} from './base'; } from './base';
import { moveHelperToHooks } from './helpers'; import { moveHelperToHooks } from './helpers';
import { wrapHelper } from './internal/wrapHelper'; import { wrapHelper } from './internal/wrapHelper';
import { import {
createProtoAccessControl, createProtoAccessControl,
resultIsAllowed resultIsAllowed,
} from './internal/proto-access'; } from './internal/proto-access';
export function checkRevision(compilerInfo) { export function checkRevision(compilerInfo) {
@@ -73,7 +73,7 @@ export function template(templateSpec, env) {
let extendedOptions = Utils.extend({}, options, { let extendedOptions = Utils.extend({}, options, {
hooks: this.hooks, hooks: this.hooks,
protoAccessControl: this.protoAccessControl protoAccessControl: this.protoAccessControl,
}); });
let result = env.VM.invokePartial.call( let result = env.VM.invokePartial.call(
@@ -115,15 +115,15 @@ export function template(templateSpec, env) {
// Just add water // Just add water
let container = { let container = {
strict: function(obj, name, loc) { strict: function (obj, name, loc) {
if (!obj || !(name in obj)) { if (!obj || !(name in obj)) {
throw new Exception('"' + name + '" not defined in ' + obj, { throw new Exception('"' + name + '" not defined in ' + obj, {
loc: loc loc: loc,
}); });
} }
return container.lookupProperty(obj, name); return container.lookupProperty(obj, name);
}, },
lookupProperty: function(parent, propertyName) { lookupProperty: function (parent, propertyName) {
let result = parent[propertyName]; let result = parent[propertyName];
if (result == null) { if (result == null) {
return result; return result;
@@ -137,7 +137,7 @@ export function template(templateSpec, env) {
} }
return undefined; return undefined;
}, },
lookup: function(depths, name) { lookup: function (depths, name) {
const len = depths.length; const len = depths.length;
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
let result = depths[i] && container.lookupProperty(depths[i], name); let result = depths[i] && container.lookupProperty(depths[i], name);
@@ -146,21 +146,21 @@ export function template(templateSpec, env) {
} }
} }
}, },
lambda: function(current, context) { lambda: function (current, context) {
return typeof current === 'function' ? current.call(context) : current; return typeof current === 'function' ? current.call(context) : current;
}, },
escapeExpression: Utils.escapeExpression, escapeExpression: Utils.escapeExpression,
invokePartial: invokePartialWrapper, invokePartial: invokePartialWrapper,
fn: function(i) { fn: function (i) {
let ret = templateSpec[i]; let ret = templateSpec[i];
ret.decorator = templateSpec[i + '_d']; ret.decorator = templateSpec[i + '_d'];
return ret; return ret;
}, },
programs: [], programs: [],
program: function(i, data, declaredBlockParams, blockParams, depths) { program: function (i, data, declaredBlockParams, blockParams, depths) {
let programWrapper = this.programs[i], let programWrapper = this.programs[i],
fn = this.fn(i); fn = this.fn(i);
if (data || depths || blockParams || declaredBlockParams) { if (data || depths || blockParams || declaredBlockParams) {
@@ -179,13 +179,13 @@ export function template(templateSpec, env) {
return programWrapper; return programWrapper;
}, },
data: function(value, depth) { data: function (value, depth) {
while (value && depth--) { while (value && depth--) {
value = value._parent; value = value._parent;
} }
return value; return value;
}, },
mergeIfNeeded: function(param, common) { mergeIfNeeded: function (param, common) {
let obj = param || common; let obj = param || common;
if (param && common && param !== common) { if (param && common && param !== common) {
@@ -198,7 +198,7 @@ export function template(templateSpec, env) {
nullContext: Object.seal({}), nullContext: Object.seal({}),
noop: env.VM.noop, noop: env.VM.noop,
compilerInfo: templateSpec.compiler compilerInfo: templateSpec.compiler,
}; };
function ret(context, options = {}) { function ret(context, options = {}) {
@@ -412,7 +412,7 @@ function executeDecorators(fn, prog, container, depths, data, blockParams) {
} }
function wrapHelpersToPassLookupProperty(mergedHelpers, container) { function wrapHelpersToPassLookupProperty(mergedHelpers, container) {
Object.keys(mergedHelpers).forEach(helperName => { Object.keys(mergedHelpers).forEach((helperName) => {
let helper = mergedHelpers[helperName]; let helper = mergedHelpers[helperName];
mergedHelpers[helperName] = passLookupPropertyOption(helper, container); mergedHelpers[helperName] = passLookupPropertyOption(helper, container);
}); });
@@ -420,7 +420,7 @@ function wrapHelpersToPassLookupProperty(mergedHelpers, container) {
function passLookupPropertyOption(helper, container) { function passLookupPropertyOption(helper, container) {
const lookupProperty = container.lookupProperty; const lookupProperty = container.lookupProperty;
return wrapHelper(helper, options => { return wrapHelper(helper, (options) => {
return Utils.extend({ lookupProperty }, options); return Utils.extend({ lookupProperty }, options);
}); });
} }
+1 -1
View File
@@ -3,7 +3,7 @@ function SafeString(string) {
this.string = string; this.string = string;
} }
SafeString.prototype.toString = SafeString.prototype.toHTML = function() { SafeString.prototype.toString = SafeString.prototype.toHTML = function () {
return '' + this.string; return '' + this.string;
}; };
+2 -2
View File
@@ -5,7 +5,7 @@ const escape = {
'"': '&quot;', '"': '&quot;',
"'": '&#x27;', "'": '&#x27;',
'`': '&#x60;', '`': '&#x60;',
'=': '&#x3D;' '=': '&#x3D;',
}; };
const badChars = /[&<>"'`=]/g, const badChars = /[&<>"'`=]/g,
@@ -38,7 +38,7 @@ export function isFunction(value) {
/* istanbul ignore next */ /* istanbul ignore next */
export const isArray = export const isArray =
Array.isArray || Array.isArray ||
function(value) { function (value) {
return value && typeof value === 'object' return value && typeof value === 'object'
? toString.call(value) === '[object Array]' ? toString.call(value) === '[object Array]'
: false; : false;
+26 -23
View File
@@ -6,12 +6,12 @@ import * as Handlebars from './handlebars';
import { basename } from 'path'; import { basename } from 'path';
import { SourceMapConsumer, SourceNode } from 'source-map'; import { SourceMapConsumer, SourceNode } from 'source-map';
module.exports.loadTemplates = function(opts, callback) { module.exports.loadTemplates = function (opts, callback) {
loadStrings(opts, function(err, strings) { loadStrings(opts, function (err, strings) {
if (err) { if (err) {
callback(err); callback(err);
} else { } else {
loadFiles(opts, function(err, files) { loadFiles(opts, function (err, files) {
if (err) { if (err) {
callback(err); callback(err);
} else { } else {
@@ -37,7 +37,7 @@ function loadStrings(opts, callback) {
Async.map( Async.map(
strings, strings,
function(string, callback) { function (string, callback) {
if (string !== '-') { if (string !== '-') {
callback(undefined, string); callback(undefined, string);
} else { } else {
@@ -45,19 +45,19 @@ function loadStrings(opts, callback) {
let buffer = ''; let buffer = '';
process.stdin.setEncoding('utf8'); process.stdin.setEncoding('utf8');
process.stdin.on('data', function(chunk) { process.stdin.on('data', function (chunk) {
buffer += chunk; buffer += chunk;
}); });
process.stdin.on('end', function() { process.stdin.on('end', function () {
callback(undefined, buffer); callback(undefined, buffer);
}); });
} }
}, },
function(err, strings) { function (err, strings) {
strings = strings.map((string, index) => ({ strings = strings.map((string, index) => ({
name: names[index], name: names[index],
path: names[index], path: names[index],
source: string source: string,
})); }));
callback(err, strings); callback(err, strings);
} }
@@ -68,20 +68,23 @@ function loadFiles(opts, callback) {
// Build file extension pattern // Build file extension pattern
let extension = (opts.extension || 'handlebars').replace( let extension = (opts.extension || 'handlebars').replace(
/[\\^$*+?.():=!|{}\-[\]]/g, /[\\^$*+?.():=!|{}\-[\]]/g,
function(arg) { function (arg) {
return '\\' + arg; return '\\' + arg;
} }
); );
extension = new RegExp('\\.' + extension + '$'); extension = new RegExp('\\.' + extension + '$');
let ret = [], let ret = [],
queue = (opts.files || []).map(template => ({ template, root: opts.root })); queue = (opts.files || []).map((template) => ({
template,
root: opts.root,
}));
Async.whilst( Async.whilst(
() => queue.length, () => queue.length,
function(callback) { function (callback) {
let { template: path, root } = queue.shift(); let { template: path, root } = queue.shift();
fs.stat(path, function(err, stat) { fs.stat(path, function (err, stat) {
if (err) { if (err) {
return callback( return callback(
new Handlebars.Exception(`Unable to open template file "${path}"`) new Handlebars.Exception(`Unable to open template file "${path}"`)
@@ -91,12 +94,12 @@ function loadFiles(opts, callback) {
if (stat.isDirectory()) { if (stat.isDirectory()) {
opts.hasDirectory = true; opts.hasDirectory = true;
fs.readdir(path, function(err, children) { fs.readdir(path, function (err, children) {
/* istanbul ignore next : Race condition that being too lazy to test */ /* istanbul ignore next : Race condition that being too lazy to test */
if (err) { if (err) {
return callback(err); return callback(err);
} }
children.forEach(function(file) { children.forEach(function (file) {
let childPath = path + '/' + file; let childPath = path + '/' + file;
if ( if (
@@ -110,7 +113,7 @@ function loadFiles(opts, callback) {
callback(); callback();
}); });
} else { } else {
fs.readFile(path, 'utf8', function(err, data) { fs.readFile(path, 'utf8', function (err, data) {
/* istanbul ignore next : Race condition that being too lazy to test */ /* istanbul ignore next : Race condition that being too lazy to test */
if (err) { if (err) {
return callback(err); return callback(err);
@@ -132,7 +135,7 @@ function loadFiles(opts, callback) {
ret.push({ ret.push({
path: path, path: path,
name: name, name: name,
source: data source: data,
}); });
callback(); callback();
@@ -140,7 +143,7 @@ function loadFiles(opts, callback) {
} }
}); });
}, },
function(err) { function (err) {
if (err) { if (err) {
callback(err); callback(err);
} else { } else {
@@ -150,7 +153,7 @@ function loadFiles(opts, callback) {
); );
} }
module.exports.cli = function(opts) { module.exports.cli = function (opts) {
if (opts.version) { if (opts.version) {
console.log(Handlebars.VERSION); console.log(Handlebars.VERSION);
return; return;
@@ -219,10 +222,10 @@ module.exports.cli = function(opts) {
output.add('{};\n'); output.add('{};\n');
} }
opts.templates.forEach(function(template) { opts.templates.forEach(function (template) {
let options = { let options = {
knownHelpers: known, knownHelpers: known,
knownHelpersOnly: opts.o knownHelpersOnly: opts.o,
}; };
if (opts.map) { if (opts.map) {
@@ -259,7 +262,7 @@ module.exports.cli = function(opts) {
template.name, template.name,
"'] = template(", "'] = template(",
precompiled, precompiled,
');\n' ');\n',
]); ]);
} }
}); });
@@ -335,7 +338,7 @@ function minify(output, sourceMapFile) {
return require('uglify-js').minify(output.code, { return require('uglify-js').minify(output.code, {
sourceMap: { sourceMap: {
content: output.map, content: output.map,
url: sourceMapFile url: sourceMapFile,
} },
}); });
} }
+1 -1
View File
@@ -5,5 +5,5 @@ module.exports = {
functions: 100, functions: 100,
statements: 100, statements: 100,
exclude: ['**/spec/**'], exclude: ['**/spec/**'],
reporter: 'html' reporter: 'html',
}; };
+11 -8
View File
@@ -51,7 +51,7 @@
"mock-stdin": "^0.3.0", "mock-stdin": "^0.3.0",
"mustache": "^2.1.3", "mustache": "^2.1.3",
"nyc": "^14.1.1", "nyc": "^14.1.1",
"prettier": "^1.19.1", "prettier": "^2.7.1",
"semver": "^5.0.1", "semver": "^5.0.1",
"sinon": "^7.5.0", "sinon": "^7.5.0",
"typescript": "^3.4.3", "typescript": "^3.4.3",
@@ -11268,15 +11268,18 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "1.19.1", "version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true, "dev": true,
"bin": { "bin": {
"prettier": "bin-prettier.js" "prettier": "bin-prettier.js"
}, },
"engines": { "engines": {
"node": ">=4" "node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
} }
}, },
"node_modules/pretty-bytes": { "node_modules/pretty-bytes": {
@@ -23629,9 +23632,9 @@
"dev": true "dev": true
}, },
"prettier": { "prettier": {
"version": "1.19.1", "version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true "dev": true
}, },
"pretty-bytes": { "pretty-bytes": {
+1 -1
View File
@@ -62,7 +62,7 @@
"mock-stdin": "^0.3.0", "mock-stdin": "^0.3.0",
"mustache": "^2.1.3", "mustache": "^2.1.3",
"nyc": "^14.1.1", "nyc": "^14.1.1",
"prettier": "^1.19.1", "prettier": "^2.7.1",
"semver": "^5.0.1", "semver": "^5.0.1",
"sinon": "^7.5.0", "sinon": "^7.5.0",
"typescript": "^3.4.3", "typescript": "^3.4.3",
+1 -1
View File
@@ -1,5 +1,5 @@
module.exports = { module.exports = {
tabWidth: 2, tabWidth: 2,
semi: true, semi: true,
singleQuote: true singleQuote: true,
}; };
+4 -4
View File
@@ -22,16 +22,16 @@ module.exports = {
strictEqual: true, strictEqual: true,
define: true, define: true,
expect: true, expect: true,
chai: true chai: true,
}, },
env: { env: {
mocha: true mocha: true,
}, },
rules: { rules: {
// Disabling for tests, for now. // Disabling for tests, for now.
'no-path-concat': 'off', 'no-path-concat': 'off',
'no-var': 'off', 'no-var': 'off',
'dot-notation': 'off' 'dot-notation': 'off',
} },
}; };
+34 -34
View File
@@ -1,14 +1,14 @@
describe('ast', function() { describe('ast', function () {
if (!Handlebars.AST) { if (!Handlebars.AST) {
return; return;
} }
var AST = Handlebars.AST; var AST = Handlebars.AST;
describe('BlockStatement', function() { describe('BlockStatement', function () {
it('should throw on mustache mismatch', function() { it('should throw on mustache mismatch', function () {
shouldThrow( shouldThrow(
function() { function () {
handlebarsEnv.parse('\n {{#foo}}{{/bar}}'); handlebarsEnv.parse('\n {{#foo}}{{/bar}}');
}, },
Handlebars.Exception, Handlebars.Exception,
@@ -17,14 +17,14 @@ describe('ast', function() {
}); });
}); });
describe('helpers', function() { describe('helpers', function () {
describe('#helperExpression', function() { describe('#helperExpression', function () {
it('should handle mustache statements', function() { it('should handle mustache statements', function () {
equals( equals(
AST.helpers.helperExpression({ AST.helpers.helperExpression({
type: 'MustacheStatement', type: 'MustacheStatement',
params: [], params: [],
hash: undefined hash: undefined,
}), }),
false false
); );
@@ -32,7 +32,7 @@ describe('ast', function() {
AST.helpers.helperExpression({ AST.helpers.helperExpression({
type: 'MustacheStatement', type: 'MustacheStatement',
params: [1], params: [1],
hash: undefined hash: undefined,
}), }),
true true
); );
@@ -40,17 +40,17 @@ describe('ast', function() {
AST.helpers.helperExpression({ AST.helpers.helperExpression({
type: 'MustacheStatement', type: 'MustacheStatement',
params: [], params: [],
hash: {} hash: {},
}), }),
true true
); );
}); });
it('should handle block statements', function() { it('should handle block statements', function () {
equals( equals(
AST.helpers.helperExpression({ AST.helpers.helperExpression({
type: 'BlockStatement', type: 'BlockStatement',
params: [], params: [],
hash: undefined hash: undefined,
}), }),
false false
); );
@@ -58,7 +58,7 @@ describe('ast', function() {
AST.helpers.helperExpression({ AST.helpers.helperExpression({
type: 'BlockStatement', type: 'BlockStatement',
params: [1], params: [1],
hash: undefined hash: undefined,
}), }),
true true
); );
@@ -66,15 +66,15 @@ describe('ast', function() {
AST.helpers.helperExpression({ AST.helpers.helperExpression({
type: 'BlockStatement', type: 'BlockStatement',
params: [], params: [],
hash: {} hash: {},
}), }),
true true
); );
}); });
it('should handle subexpressions', function() { it('should handle subexpressions', function () {
equals(AST.helpers.helperExpression({ type: 'SubExpression' }), true); equals(AST.helpers.helperExpression({ type: 'SubExpression' }), true);
}); });
it('should work with non-helper nodes', function() { it('should work with non-helper nodes', function () {
equals(AST.helpers.helperExpression({ type: 'Program' }), false); equals(AST.helpers.helperExpression({ type: 'Program' }), false);
equals( equals(
@@ -107,7 +107,7 @@ describe('ast', function() {
}); });
}); });
describe('Line Numbers', function() { describe('Line Numbers', function () {
var ast, body; var ast, body;
function testColumns(node, firstLine, lastLine, firstColumn, lastColumn) { function testColumns(node, firstLine, lastLine, firstColumn, lastColumn) {
@@ -120,59 +120,59 @@ describe('ast', function() {
/* eslint-disable no-multi-spaces */ /* eslint-disable no-multi-spaces */
ast = Handlebars.parse( ast = Handlebars.parse(
'line 1 {{line1Token}}\n' + // 1 'line 1 {{line1Token}}\n' + // 1
' line 2 {{line2token}}\n' + // 2 ' line 2 {{line2token}}\n' + // 2
' line 3 {{#blockHelperOnLine3}}\n' + // 3 ' line 3 {{#blockHelperOnLine3}}\n' + // 3
'line 4{{line4token}}\n' + // 4 'line 4{{line4token}}\n' + // 4
'line5{{else}}\n' + // 5 'line5{{else}}\n' + // 5
'{{line6Token}}\n' + // 6 '{{line6Token}}\n' + // 6
'{{/blockHelperOnLine3}}\n' + // 7 '{{/blockHelperOnLine3}}\n' + // 7
'{{#open}}\n' + // 8 '{{#open}}\n' + // 8
'{{else inverse}}\n' + // 9 '{{else inverse}}\n' + // 9
'{{else}}\n' + // 10 '{{else}}\n' + // 10
'{{/open}}' '{{/open}}'
); // 11 ); // 11
/* eslint-enable no-multi-spaces */ /* eslint-enable no-multi-spaces */
body = ast.body; body = ast.body;
it('gets ContentNode line numbers', function() { it('gets ContentNode line numbers', function () {
var contentNode = body[0]; var contentNode = body[0];
testColumns(contentNode, 1, 1, 0, 7); testColumns(contentNode, 1, 1, 0, 7);
}); });
it('gets MustacheStatement line numbers', function() { it('gets MustacheStatement line numbers', function () {
var mustacheNode = body[1]; var mustacheNode = body[1];
testColumns(mustacheNode, 1, 1, 7, 21); 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); 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]; var secondMustacheStatement = body[3];
testColumns(secondMustacheStatement, 2, 2, 8, 22); 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]; var blockHelperNode = body[5];
testColumns(blockHelperNode, 3, 7, 8, 23); 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], var blockHelperNode = body[5],
program = blockHelperNode.program; program = blockHelperNode.program;
testColumns(program, 3, 5, 31, 5); testColumns(program, 3, 5, 31, 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], var blockHelperNode = body[5],
inverse = blockHelperNode.inverse; inverse = blockHelperNode.inverse;
testColumns(inverse, 5, 7, 13, 0); testColumns(inverse, 5, 7, 13, 0);
}); });
it('correctly records the line number of chained inverses', function() { it('correctly records the line number of chained inverses', function () {
var chainInverseNode = body[7]; var chainInverseNode = body[7];
testColumns(chainInverseNode.program, 8, 9, 9, 0); testColumns(chainInverseNode.program, 8, 9, 9, 0);
+102 -124
View File
@@ -1,17 +1,15 @@
global.handlebarsEnv = null; global.handlebarsEnv = null;
beforeEach(function() { beforeEach(function () {
global.handlebarsEnv = Handlebars.create(); global.handlebarsEnv = Handlebars.create();
}); });
describe('basic context', function() { describe('basic context', function () {
it('most basic', function() { it('most basic', function () {
expectTemplate('{{foo}}') expectTemplate('{{foo}}').withInput({ foo: 'foo' }).toCompileTo('foo');
.withInput({ foo: 'foo' })
.toCompileTo('foo');
}); });
it('escaping', function() { it('escaping', function () {
expectTemplate('\\{{foo}}') expectTemplate('\\{{foo}}')
.withInput({ foo: 'food' }) .withInput({ foo: 'food' })
.toCompileTo('{{foo}}'); .toCompileTo('{{foo}}');
@@ -33,23 +31,21 @@ describe('basic context', function() {
.toCompileTo('\\\\ food'); .toCompileTo('\\\\ food');
}); });
it('compiling with a basic context', function() { it('compiling with a basic context', function () {
expectTemplate('Goodbye\n{{cruel}}\n{{world}}!') expectTemplate('Goodbye\n{{cruel}}\n{{world}}!')
.withInput({ .withInput({
cruel: 'cruel', cruel: 'cruel',
world: 'world' world: 'world',
}) })
.withMessage('It works if all the required keys are provided') .withMessage('It works if all the required keys are provided')
.toCompileTo('Goodbye\ncruel\nworld!'); .toCompileTo('Goodbye\ncruel\nworld!');
}); });
it('compiling with a string context', function() { it('compiling with a string context', function () {
expectTemplate('{{.}}{{length}}') expectTemplate('{{.}}{{length}}').withInput('bye').toCompileTo('bye3');
.withInput('bye')
.toCompileTo('bye3');
}); });
it('compiling with an undefined context', function() { it('compiling with an undefined context', function () {
expectTemplate('Goodbye\n{{cruel}}\n{{world.bar}}!') expectTemplate('Goodbye\n{{cruel}}\n{{world.bar}}!')
.withInput(undefined) .withInput(undefined)
.toCompileTo('Goodbye\n\n!'); .toCompileTo('Goodbye\n\n!');
@@ -59,11 +55,11 @@ describe('basic context', function() {
.toCompileTo('Goodbye'); .toCompileTo('Goodbye');
}); });
it('comments', function() { it('comments', function () {
expectTemplate('{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!') expectTemplate('{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!')
.withInput({ .withInput({
cruel: 'cruel', cruel: 'cruel',
world: 'world' world: 'world',
}) })
.withMessage('comments are ignored') .withMessage('comments are ignored')
.toCompileTo('Goodbye\ncruel\nworld!'); .toCompileTo('Goodbye\ncruel\nworld!');
@@ -87,12 +83,12 @@ describe('basic context', function() {
); );
}); });
it('boolean', function() { it('boolean', function () {
var string = '{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!'; var string = '{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!';
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: true, goodbye: true,
world: 'world' world: 'world',
}) })
.withMessage('booleans show the contents when true') .withMessage('booleans show the contents when true')
.toCompileTo('GOODBYE cruel world!'); .toCompileTo('GOODBYE cruel world!');
@@ -100,41 +96,37 @@ describe('basic context', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: false, goodbye: false,
world: 'world' world: 'world',
}) })
.withMessage('booleans do not show the contents when false') .withMessage('booleans do not show the contents when false')
.toCompileTo('cruel world!'); .toCompileTo('cruel world!');
}); });
it('zeros', function() { it('zeros', function () {
expectTemplate('num1: {{num1}}, num2: {{num2}}') expectTemplate('num1: {{num1}}, num2: {{num2}}')
.withInput({ .withInput({
num1: 42, num1: 42,
num2: 0 num2: 0,
}) })
.toCompileTo('num1: 42, num2: 0'); .toCompileTo('num1: 42, num2: 0');
expectTemplate('num: {{.}}') expectTemplate('num: {{.}}').withInput(0).toCompileTo('num: 0');
.withInput(0)
.toCompileTo('num: 0');
expectTemplate('num: {{num1/num2}}') expectTemplate('num: {{num1/num2}}')
.withInput({ num1: { num2: 0 } }) .withInput({ num1: { num2: 0 } })
.toCompileTo('num: 0'); .toCompileTo('num: 0');
}); });
it('false', function() { it('false', function () {
/* eslint-disable no-new-wrappers */ /* eslint-disable no-new-wrappers */
expectTemplate('val1: {{val1}}, val2: {{val2}}') expectTemplate('val1: {{val1}}, val2: {{val2}}')
.withInput({ .withInput({
val1: false, val1: false,
val2: new Boolean(false) val2: new Boolean(false),
}) })
.toCompileTo('val1: false, val2: false'); .toCompileTo('val1: false, val2: false');
expectTemplate('val: {{.}}') expectTemplate('val: {{.}}').withInput(false).toCompileTo('val: false');
.withInput(false)
.toCompileTo('val: false');
expectTemplate('val: {{val1/val2}}') expectTemplate('val: {{val1/val2}}')
.withInput({ val1: { val2: false } }) .withInput({ val1: { val2: false } })
@@ -143,7 +135,7 @@ describe('basic context', function() {
expectTemplate('val1: {{{val1}}}, val2: {{{val2}}}') expectTemplate('val1: {{{val1}}}, val2: {{{val2}}}')
.withInput({ .withInput({
val1: false, val1: false,
val2: new Boolean(false) val2: new Boolean(false),
}) })
.toCompileTo('val1: false, val2: false'); .toCompileTo('val1: false, val2: false');
@@ -153,10 +145,10 @@ describe('basic context', function() {
/* eslint-enable */ /* eslint-enable */
}); });
it('should handle undefined and null', function() { it('should handle undefined and null', function () {
expectTemplate('{{awesome undefined null}}') expectTemplate('{{awesome undefined null}}')
.withInput({ .withInput({
awesome: function(_undefined, _null, options) { awesome: function (_undefined, _null, options) {
return ( return (
(_undefined === undefined) + (_undefined === undefined) +
' ' + ' ' +
@@ -164,34 +156,34 @@ describe('basic context', function() {
' ' + ' ' +
typeof options typeof options
); );
} },
}) })
.toCompileTo('true true object'); .toCompileTo('true true object');
expectTemplate('{{undefined}}') expectTemplate('{{undefined}}')
.withInput({ .withInput({
undefined: function() { undefined: function () {
return 'undefined!'; return 'undefined!';
} },
}) })
.toCompileTo('undefined!'); .toCompileTo('undefined!');
expectTemplate('{{null}}') expectTemplate('{{null}}')
.withInput({ .withInput({
null: function() { null: function () {
return 'null!'; return 'null!';
} },
}) })
.toCompileTo('null!'); .toCompileTo('null!');
}); });
it('newlines', function() { it('newlines', function () {
expectTemplate("Alan's\nTest").toCompileTo("Alan's\nTest"); expectTemplate("Alan's\nTest").toCompileTo("Alan's\nTest");
expectTemplate("Alan's\rTest").toCompileTo("Alan's\rTest"); expectTemplate("Alan's\rTest").toCompileTo("Alan's\rTest");
}); });
it('escaping text', function() { it('escaping text', function () {
expectTemplate("Awesome's") expectTemplate("Awesome's")
.withMessage( .withMessage(
"text is escaped so that it doesn't get caught on single quotes" "text is escaped so that it doesn't get caught on single quotes"
@@ -216,7 +208,7 @@ describe('basic context', function() {
.toCompileTo(" ' ' "); .toCompileTo(" ' ' ");
}); });
it('escaping expressions', function() { it('escaping expressions', function () {
expectTemplate('{{{awesome}}}') expectTemplate('{{{awesome}}}')
.withInput({ awesome: "&'\\<>" }) .withInput({ awesome: "&'\\<>" })
.withMessage("expressions with 3 handlebars aren't escaped") .withMessage("expressions with 3 handlebars aren't escaped")
@@ -238,140 +230,140 @@ describe('basic context', function() {
.toCompileTo('Escaped, &lt;b&gt; looks like: &amp;lt;b&amp;gt;'); .toCompileTo('Escaped, &lt;b&gt; looks like: &amp;lt;b&amp;gt;');
}); });
it("functions returning safestrings shouldn't be escaped", function() { it("functions returning safestrings shouldn't be escaped", function () {
expectTemplate('{{awesome}}') expectTemplate('{{awesome}}')
.withInput({ .withInput({
awesome: function() { awesome: function () {
return new Handlebars.SafeString("&'\\<>"); return new Handlebars.SafeString("&'\\<>");
} },
}) })
.withMessage("functions returning safestrings aren't escaped") .withMessage("functions returning safestrings aren't escaped")
.toCompileTo("&'\\<>"); .toCompileTo("&'\\<>");
}); });
it('functions', function() { it('functions', function () {
expectTemplate('{{awesome}}') expectTemplate('{{awesome}}')
.withInput({ .withInput({
awesome: function() { awesome: function () {
return 'Awesome'; return 'Awesome';
} },
}) })
.withMessage('functions are called and render their output') .withMessage('functions are called and render their output')
.toCompileTo('Awesome'); .toCompileTo('Awesome');
expectTemplate('{{awesome}}') expectTemplate('{{awesome}}')
.withInput({ .withInput({
awesome: function() { awesome: function () {
return this.more; return this.more;
}, },
more: 'More awesome' more: 'More awesome',
}) })
.withMessage('functions are bound to the context') .withMessage('functions are bound to the context')
.toCompileTo('More awesome'); .toCompileTo('More awesome');
}); });
it('functions with context argument', function() { it('functions with context argument', function () {
expectTemplate('{{awesome frank}}') expectTemplate('{{awesome frank}}')
.withInput({ .withInput({
awesome: function(context) { awesome: function (context) {
return context; return context;
}, },
frank: 'Frank' frank: 'Frank',
}) })
.withMessage('functions are called with context arguments') .withMessage('functions are called with context arguments')
.toCompileTo('Frank'); .toCompileTo('Frank');
}); });
it('pathed functions with context argument', function() { it('pathed functions with context argument', function () {
expectTemplate('{{bar.awesome frank}}') expectTemplate('{{bar.awesome frank}}')
.withInput({ .withInput({
bar: { bar: {
awesome: function(context) { awesome: function (context) {
return context; return context;
} },
}, },
frank: 'Frank' frank: 'Frank',
}) })
.withMessage('functions are called with context arguments') .withMessage('functions are called with context arguments')
.toCompileTo('Frank'); .toCompileTo('Frank');
}); });
it('depthed functions with context argument', function() { it('depthed functions with context argument', function () {
expectTemplate('{{#with frank}}{{../awesome .}}{{/with}}') expectTemplate('{{#with frank}}{{../awesome .}}{{/with}}')
.withInput({ .withInput({
awesome: function(context) { awesome: function (context) {
return context; return context;
}, },
frank: 'Frank' frank: 'Frank',
}) })
.withMessage('functions are called with context arguments') .withMessage('functions are called with context arguments')
.toCompileTo('Frank'); .toCompileTo('Frank');
}); });
it('block functions with context argument', function() { it('block functions with context argument', function () {
expectTemplate('{{#awesome 1}}inner {{.}}{{/awesome}}') expectTemplate('{{#awesome 1}}inner {{.}}{{/awesome}}')
.withInput({ .withInput({
awesome: function(context, options) { awesome: function (context, options) {
return options.fn(context); return options.fn(context);
} },
}) })
.withMessage('block functions are called with context and options') .withMessage('block functions are called with context and options')
.toCompileTo('inner 1'); .toCompileTo('inner 1');
}); });
it('depthed block functions with context argument', function() { it('depthed block functions with context argument', function () {
expectTemplate( expectTemplate(
'{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}' '{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}'
) )
.withInput({ .withInput({
value: true, value: true,
awesome: function(context, options) { awesome: function (context, options) {
return options.fn(context); return options.fn(context);
} },
}) })
.withMessage('block functions are called with context and options') .withMessage('block functions are called with context and options')
.toCompileTo('inner 1'); .toCompileTo('inner 1');
}); });
it('block functions without context argument', function() { it('block functions without context argument', function () {
expectTemplate('{{#awesome}}inner{{/awesome}}') expectTemplate('{{#awesome}}inner{{/awesome}}')
.withInput({ .withInput({
awesome: function(options) { awesome: function (options) {
return options.fn(this); return options.fn(this);
} },
}) })
.withMessage('block functions are called with options') .withMessage('block functions are called with options')
.toCompileTo('inner'); .toCompileTo('inner');
}); });
it('pathed block functions without context argument', function() { it('pathed block functions without context argument', function () {
expectTemplate('{{#foo.awesome}}inner{{/foo.awesome}}') expectTemplate('{{#foo.awesome}}inner{{/foo.awesome}}')
.withInput({ .withInput({
foo: { foo: {
awesome: function() { awesome: function () {
return this; return this;
} },
} },
}) })
.withMessage('block functions are called with options') .withMessage('block functions are called with options')
.toCompileTo('inner'); .toCompileTo('inner');
}); });
it('depthed block functions without context argument', function() { it('depthed block functions without context argument', function () {
expectTemplate( expectTemplate(
'{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}' '{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}'
) )
.withInput({ .withInput({
value: true, value: true,
awesome: function() { awesome: function () {
return this; return this;
} },
}) })
.withMessage('block functions are called with options') .withMessage('block functions are called with options')
.toCompileTo('inner'); .toCompileTo('inner');
}); });
it('paths with hyphens', function() { it('paths with hyphens', function () {
expectTemplate('{{foo-bar}}') expectTemplate('{{foo-bar}}')
.withInput({ 'foo-bar': 'baz' }) .withInput({ 'foo-bar': 'baz' })
.withMessage('Paths can contain hyphens (-)') .withMessage('Paths can contain hyphens (-)')
@@ -388,21 +380,21 @@ describe('basic context', function() {
.toCompileTo('baz'); .toCompileTo('baz');
}); });
it('nested paths', function() { it('nested paths', function () {
expectTemplate('Goodbye {{alan/expression}} world!') expectTemplate('Goodbye {{alan/expression}} world!')
.withInput({ alan: { expression: 'beautiful' } }) .withInput({ alan: { expression: 'beautiful' } })
.withMessage('Nested paths access nested objects') .withMessage('Nested paths access nested objects')
.toCompileTo('Goodbye beautiful world!'); .toCompileTo('Goodbye beautiful world!');
}); });
it('nested paths with empty string value', function() { it('nested paths with empty string value', function () {
expectTemplate('Goodbye {{alan/expression}} world!') expectTemplate('Goodbye {{alan/expression}} world!')
.withInput({ alan: { expression: '' } }) .withInput({ alan: { expression: '' } })
.withMessage('Nested paths access nested objects with empty string') .withMessage('Nested paths access nested objects with empty string')
.toCompileTo('Goodbye world!'); .toCompileTo('Goodbye world!');
}); });
it('literal paths', function() { it('literal paths', function () {
expectTemplate('Goodbye {{[@alan]/expression}} world!') expectTemplate('Goodbye {{[@alan]/expression}} world!')
.withInput({ '@alan': { expression: 'beautiful' } }) .withInput({ '@alan': { expression: 'beautiful' } })
.withMessage('Literal paths can be used') .withMessage('Literal paths can be used')
@@ -414,7 +406,7 @@ describe('basic context', function() {
.toCompileTo('Goodbye beautiful world!'); .toCompileTo('Goodbye beautiful world!');
}); });
it('literal references', function() { it('literal references', function () {
expectTemplate('Goodbye {{[foo bar]}} world!') expectTemplate('Goodbye {{[foo bar]}} world!')
.withInput({ 'foo bar': 'beautiful' }) .withInput({ 'foo bar': 'beautiful' })
.toCompileTo('Goodbye beautiful world!'); .toCompileTo('Goodbye beautiful world!');
@@ -440,24 +432,22 @@ describe('basic context', function() {
.toCompileTo('Goodbye beautiful world!'); .toCompileTo('Goodbye beautiful world!');
}); });
it("that current context path ({{.}}) doesn't hit helpers", function() { it("that current context path ({{.}}) doesn't hit helpers", function () {
expectTemplate('test: {{.}}') expectTemplate('test: {{.}}')
.withInput(null) .withInput(null)
.withHelpers({ helper: 'awesome' }) .withHelpers({ helper: 'awesome' })
.toCompileTo('test: '); .toCompileTo('test: ');
}); });
it('complex but empty paths', function() { it('complex but empty paths', function () {
expectTemplate('{{person/name}}') expectTemplate('{{person/name}}')
.withInput({ person: { name: null } }) .withInput({ person: { name: null } })
.toCompileTo(''); .toCompileTo('');
expectTemplate('{{person/name}}') expectTemplate('{{person/name}}').withInput({ person: {} }).toCompileTo('');
.withInput({ person: {} })
.toCompileTo('');
}); });
it('this keyword in paths', function() { it('this keyword in paths', function () {
expectTemplate('{{#goodbyes}}{{this}}{{/goodbyes}}') expectTemplate('{{#goodbyes}}{{this}}{{/goodbyes}}')
.withInput({ goodbyes: ['goodbye', 'Goodbye', 'GOODBYE'] }) .withInput({ goodbyes: ['goodbye', 'Goodbye', 'GOODBYE'] })
.withMessage('This keyword in paths evaluates to current context') .withMessage('This keyword in paths evaluates to current context')
@@ -465,32 +455,30 @@ describe('basic context', function() {
expectTemplate('{{#hellos}}{{this/text}}{{/hellos}}') expectTemplate('{{#hellos}}{{this/text}}{{/hellos}}')
.withInput({ .withInput({
hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }] hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }],
}) })
.withMessage('This keyword evaluates in more complex paths') .withMessage('This keyword evaluates in more complex paths')
.toCompileTo('helloHelloHELLO'); .toCompileTo('helloHelloHELLO');
}); });
it('this keyword nested inside path', function() { it('this keyword nested inside path', function () {
expectTemplate('{{#hellos}}{{text/this/foo}}{{/hellos}}').toThrow( expectTemplate('{{#hellos}}{{text/this/foo}}{{/hellos}}').toThrow(
Error, Error,
'Invalid path: text/this - 1:13' 'Invalid path: text/this - 1:13'
); );
expectTemplate('{{[this]}}') expectTemplate('{{[this]}}').withInput({ this: 'bar' }).toCompileTo('bar');
.withInput({ this: 'bar' })
.toCompileTo('bar');
expectTemplate('{{text/[this]}}') expectTemplate('{{text/[this]}}')
.withInput({ text: { this: 'bar' } }) .withInput({ text: { this: 'bar' } })
.toCompileTo('bar'); .toCompileTo('bar');
}); });
it('this keyword in helpers', function() { it('this keyword in helpers', function () {
var helpers = { var helpers = {
foo: function(value) { foo: function (value) {
return 'bar ' + value; return 'bar ' + value;
} },
}; };
expectTemplate('{{#goodbyes}}{{foo this}}{{/goodbyes}}') expectTemplate('{{#goodbyes}}{{foo this}}{{/goodbyes}}')
@@ -501,14 +489,14 @@ describe('basic context', function() {
expectTemplate('{{#hellos}}{{foo this/text}}{{/hellos}}') expectTemplate('{{#hellos}}{{foo this/text}}{{/hellos}}')
.withInput({ .withInput({
hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }] hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }],
}) })
.withHelpers(helpers) .withHelpers(helpers)
.withMessage('This keyword evaluates in more complex paths') .withMessage('This keyword evaluates in more complex paths')
.toCompileTo('bar hellobar Hellobar HELLO'); .toCompileTo('bar hellobar Hellobar HELLO');
}); });
it('this keyword nested inside helpers param', function() { it('this keyword nested inside helpers param', function () {
expectTemplate('{{#hellos}}{{foo text/this/foo}}{{/hellos}}').toThrow( expectTemplate('{{#hellos}}{{foo text/this/foo}}{{/hellos}}').toThrow(
Error, Error,
'Invalid path: text/this - 1:17' 'Invalid path: text/this - 1:17'
@@ -516,79 +504,69 @@ describe('basic context', function() {
expectTemplate('{{foo [this]}}') expectTemplate('{{foo [this]}}')
.withInput({ .withInput({
foo: function(value) { foo: function (value) {
return value; return value;
}, },
this: 'bar' this: 'bar',
}) })
.toCompileTo('bar'); .toCompileTo('bar');
expectTemplate('{{foo text/[this]}}') expectTemplate('{{foo text/[this]}}')
.withInput({ .withInput({
foo: function(value) { foo: function (value) {
return value; return value;
}, },
text: { this: 'bar' } text: { this: 'bar' },
}) })
.toCompileTo('bar'); .toCompileTo('bar');
}); });
it('pass string literals', function() { it('pass string literals', function () {
expectTemplate('{{"foo"}}').toCompileTo(''); expectTemplate('{{"foo"}}').toCompileTo('');
expectTemplate('{{"foo"}}') expectTemplate('{{"foo"}}').withInput({ foo: 'bar' }).toCompileTo('bar');
.withInput({ foo: 'bar' })
.toCompileTo('bar');
expectTemplate('{{#"foo"}}{{.}}{{/"foo"}}') expectTemplate('{{#"foo"}}{{.}}{{/"foo"}}')
.withInput({ .withInput({
foo: ['bar', 'baz'] foo: ['bar', 'baz'],
}) })
.toCompileTo('barbaz'); .toCompileTo('barbaz');
}); });
it('pass number literals', function() { it('pass number literals', function () {
expectTemplate('{{12}}').toCompileTo(''); expectTemplate('{{12}}').toCompileTo('');
expectTemplate('{{12}}') expectTemplate('{{12}}').withInput({ 12: 'bar' }).toCompileTo('bar');
.withInput({ '12': 'bar' })
.toCompileTo('bar');
expectTemplate('{{12.34}}').toCompileTo(''); expectTemplate('{{12.34}}').toCompileTo('');
expectTemplate('{{12.34}}') expectTemplate('{{12.34}}').withInput({ 12.34: 'bar' }).toCompileTo('bar');
.withInput({ '12.34': 'bar' })
.toCompileTo('bar');
expectTemplate('{{12.34 1}}') expectTemplate('{{12.34 1}}')
.withInput({ .withInput({
'12.34': function(arg) { 12.34: function (arg) {
return 'bar' + arg; return 'bar' + arg;
} },
}) })
.toCompileTo('bar1'); .toCompileTo('bar1');
}); });
it('pass boolean literals', function() { it('pass boolean literals', function () {
expectTemplate('{{true}}').toCompileTo(''); expectTemplate('{{true}}').toCompileTo('');
expectTemplate('{{true}}') expectTemplate('{{true}}').withInput({ '': 'foo' }).toCompileTo('');
.withInput({ '': 'foo' })
.toCompileTo('');
expectTemplate('{{false}}') expectTemplate('{{false}}').withInput({ false: 'foo' }).toCompileTo('foo');
.withInput({ false: 'foo' })
.toCompileTo('foo');
}); });
it('should handle literals in subexpression', function() { it('should handle literals in subexpression', function () {
expectTemplate('{{foo (false)}}') expectTemplate('{{foo (false)}}')
.withInput({ .withInput({
false: function() { false: function () {
return 'bar'; return 'bar';
} },
}) })
.withHelper('foo', function(arg) { .withHelper('foo', function (arg) {
return arg; return arg;
}) })
.toCompileTo('bar'); .toCompileTo('bar');
+84 -84
View File
@@ -1,5 +1,5 @@
describe('blocks', function() { describe('blocks', function () {
it('array', function() { it('array', function () {
var string = '{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!'; var string = '{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!';
expectTemplate(string) expectTemplate(string)
@@ -7,9 +7,9 @@ describe('blocks', function() {
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withMessage('Arrays iterate over the contents when not empty') .withMessage('Arrays iterate over the contents when not empty')
.toCompileTo('goodbye! Goodbye! GOODBYE! cruel world!'); .toCompileTo('goodbye! Goodbye! GOODBYE! cruel world!');
@@ -17,13 +17,13 @@ describe('blocks', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbyes: [], goodbyes: [],
world: 'world' world: 'world',
}) })
.withMessage('Arrays ignore the contents when empty') .withMessage('Arrays ignore the contents when empty')
.toCompileTo('cruel world!'); .toCompileTo('cruel world!');
}); });
it('array without data', function() { it('array without data', function () {
expectTemplate( expectTemplate(
'{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}' '{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}'
) )
@@ -31,15 +31,15 @@ describe('blocks', function() {
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withCompileOptions({ compat: false }) .withCompileOptions({ compat: false })
.toCompileTo('goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE'); .toCompileTo('goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE');
}); });
it('array with @index', function() { it('array with @index', function () {
expectTemplate( expectTemplate(
'{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!' '{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!'
) )
@@ -47,15 +47,15 @@ describe('blocks', function() {
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withMessage('The @index variable is used') .withMessage('The @index variable is used')
.toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!'); .toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!');
}); });
it('empty block', function() { it('empty block', function () {
var string = '{{#goodbyes}}{{/goodbyes}}cruel {{world}}!'; var string = '{{#goodbyes}}{{/goodbyes}}cruel {{world}}!';
expectTemplate(string) expectTemplate(string)
@@ -63,9 +63,9 @@ describe('blocks', function() {
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withMessage('Arrays iterate over the contents when not empty') .withMessage('Arrays iterate over the contents when not empty')
.toCompileTo('cruel world!'); .toCompileTo('cruel world!');
@@ -73,21 +73,21 @@ describe('blocks', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbyes: [], goodbyes: [],
world: 'world' world: 'world',
}) })
.withMessage('Arrays ignore the contents when empty') .withMessage('Arrays ignore the contents when empty')
.toCompileTo('cruel world!'); .toCompileTo('cruel world!');
}); });
it('block with complex lookup', function() { it('block with complex lookup', function () {
expectTemplate('{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}') expectTemplate('{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}')
.withInput({ .withInput({
name: 'Alan', name: 'Alan',
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
] ],
}) })
.withMessage( .withMessage(
'Templates can access variables in contexts up the stack with relative path syntax' 'Templates can access variables in contexts up the stack with relative path syntax'
@@ -97,37 +97,37 @@ describe('blocks', function() {
); );
}); });
it('multiple blocks with complex lookup', function() { it('multiple blocks with complex lookup', function () {
expectTemplate('{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}') expectTemplate('{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}')
.withInput({ .withInput({
name: 'Alan', name: 'Alan',
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
] ],
}) })
.toCompileTo('AlanAlanAlanAlanAlanAlan'); .toCompileTo('AlanAlanAlanAlanAlanAlan');
}); });
it('block with complex lookup using nested context', function() { it('block with complex lookup using nested context', function () {
expectTemplate( expectTemplate(
'{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}' '{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}'
).toThrow(Error); ).toThrow(Error);
}); });
it('block with deep nested complex lookup', function() { it('block with deep nested complex lookup', function () {
expectTemplate( expectTemplate(
'{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}' '{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}'
) )
.withInput({ .withInput({
omg: 'OMG!', omg: 'OMG!',
outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }] outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }],
}) })
.toCompileTo('Goodbye cruel sad OMG!'); .toCompileTo('Goodbye cruel sad OMG!');
}); });
it('works with cached blocks', function() { it('works with cached blocks', function () {
expectTemplate( expectTemplate(
'{{#each person}}{{#with .}}{{first}} {{last}}{{/with}}{{/each}}' '{{#each person}}{{#with .}}{{first}} {{last}}{{/with}}{{/each}}'
) )
@@ -135,14 +135,14 @@ describe('blocks', function() {
.withInput({ .withInput({
person: [ person: [
{ first: 'Alan', last: 'Johnson' }, { first: 'Alan', last: 'Johnson' },
{ first: 'Alan', last: 'Johnson' } { first: 'Alan', last: 'Johnson' },
] ],
}) })
.toCompileTo('Alan JohnsonAlan Johnson'); .toCompileTo('Alan JohnsonAlan Johnson');
}); });
describe('inverted sections', function() { describe('inverted sections', function () {
it('inverted sections with unset value', function() { it('inverted sections with unset value', function () {
expectTemplate( expectTemplate(
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}' '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}'
) )
@@ -150,7 +150,7 @@ describe('blocks', function() {
.toCompileTo('Right On!'); .toCompileTo('Right On!');
}); });
it('inverted section with false value', function() { it('inverted section with false value', function () {
expectTemplate( expectTemplate(
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}' '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}'
) )
@@ -159,7 +159,7 @@ describe('blocks', function() {
.toCompileTo('Right On!'); .toCompileTo('Right On!');
}); });
it('inverted section with empty set', function() { it('inverted section with empty set', function () {
expectTemplate( expectTemplate(
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}' '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}'
) )
@@ -168,13 +168,13 @@ describe('blocks', function() {
.toCompileTo('Right On!'); .toCompileTo('Right On!');
}); });
it('block inverted sections', function() { it('block inverted sections', function () {
expectTemplate('{{#people}}{{name}}{{^}}{{none}}{{/people}}') expectTemplate('{{#people}}{{name}}{{^}}{{none}}{{/people}}')
.withInput({ none: 'No people' }) .withInput({ none: 'No people' })
.toCompileTo('No people'); .toCompileTo('No people');
}); });
it('chained inverted sections', function() { it('chained inverted sections', function () {
expectTemplate('{{#people}}{{name}}{{else if none}}{{none}}{{/people}}') expectTemplate('{{#people}}{{name}}{{else if none}}{{none}}{{/people}}')
.withInput({ none: 'No people' }) .withInput({ none: 'No people' })
.toCompileTo('No people'); .toCompileTo('No people');
@@ -192,24 +192,24 @@ describe('blocks', function() {
.toCompileTo('No people'); .toCompileTo('No people');
}); });
it('chained inverted sections with mismatch', function() { it('chained inverted sections with mismatch', function () {
expectTemplate( expectTemplate(
'{{#people}}{{name}}{{else if none}}{{none}}{{/if}}' '{{#people}}{{name}}{{else if none}}{{none}}{{/if}}'
).toThrow(Error); ).toThrow(Error);
}); });
it('block inverted sections with empty arrays', function() { it('block inverted sections with empty arrays', function () {
expectTemplate('{{#people}}{{name}}{{^}}{{none}}{{/people}}') expectTemplate('{{#people}}{{name}}{{^}}{{none}}{{/people}}')
.withInput({ .withInput({
none: 'No people', none: 'No people',
people: [] people: [],
}) })
.toCompileTo('No people'); .toCompileTo('No people');
}); });
}); });
describe('standalone sections', function() { describe('standalone sections', function () {
it('block standalone else sections', function() { it('block standalone else sections', function () {
expectTemplate('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n') expectTemplate('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n')
.withInput({ none: 'No people' }) .withInput({ none: 'No people' })
.toCompileTo('No people\n'); .toCompileTo('No people\n');
@@ -223,7 +223,7 @@ describe('blocks', function() {
.toCompileTo('No people\n'); .toCompileTo('No people\n');
}); });
it('block standalone else sections can be disabled', function() { it('block standalone else sections can be disabled', function () {
expectTemplate('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n') expectTemplate('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n')
.withInput({ none: 'No people' }) .withInput({ none: 'No people' })
.withCompileOptions({ ignoreStandalone: true }) .withCompileOptions({ ignoreStandalone: true })
@@ -235,7 +235,7 @@ describe('blocks', function() {
.toCompileTo('\nNo people\n\n'); .toCompileTo('\nNo people\n\n');
}); });
it('block standalone chained else sections', function() { it('block standalone chained else sections', function () {
expectTemplate( expectTemplate(
'{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{/people}}\n' '{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{/people}}\n'
) )
@@ -249,17 +249,17 @@ describe('blocks', function() {
.toCompileTo('No people\n'); .toCompileTo('No people\n');
}); });
it('should handle nesting', function() { it('should handle nesting', function () {
expectTemplate('{{#data}}\n{{#if true}}\n{{.}}\n{{/if}}\n{{/data}}\nOK.') expectTemplate('{{#data}}\n{{#if true}}\n{{.}}\n{{/if}}\n{{/data}}\nOK.')
.withInput({ .withInput({
data: [1, 3, 5] data: [1, 3, 5],
}) })
.toCompileTo('1\n3\n5\nOK.'); .toCompileTo('1\n3\n5\nOK.');
}); });
}); });
describe('compat mode', function() { describe('compat mode', function () {
it('block with deep recursive lookup lookup', function() { it('block with deep recursive lookup lookup', function () {
expectTemplate( expectTemplate(
'{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}' '{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}'
) )
@@ -268,108 +268,108 @@ describe('blocks', function() {
.toCompileTo('Goodbye cruel OMG!'); .toCompileTo('Goodbye cruel OMG!');
}); });
it('block with deep recursive pathed lookup', function() { it('block with deep recursive pathed lookup', function () {
expectTemplate( expectTemplate(
'{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}' '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}'
) )
.withInput({ .withInput({
omg: { yes: 'OMG!' }, omg: { yes: 'OMG!' },
outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }],
}) })
.withCompileOptions({ compat: true }) .withCompileOptions({ compat: true })
.toCompileTo('Goodbye cruel OMG!'); .toCompileTo('Goodbye cruel OMG!');
}); });
it('block with missed recursive lookup', function() { it('block with missed recursive lookup', function () {
expectTemplate( expectTemplate(
'{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}' '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}'
) )
.withInput({ .withInput({
omg: { no: 'OMG!' }, omg: { no: 'OMG!' },
outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }],
}) })
.withCompileOptions({ compat: true }) .withCompileOptions({ compat: true })
.toCompileTo('Goodbye cruel '); .toCompileTo('Goodbye cruel ');
}); });
}); });
describe('decorators', function() { describe('decorators', function () {
it('should apply mustache decorators', function() { it('should apply mustache decorators', function () {
expectTemplate('{{#helper}}{{*decorator}}{{/helper}}') expectTemplate('{{#helper}}{{*decorator}}{{/helper}}')
.withHelper('helper', function(options) { .withHelper('helper', function (options) {
return options.fn.run; return options.fn.run;
}) })
.withDecorator('decorator', function(fn) { .withDecorator('decorator', function (fn) {
fn.run = 'success'; fn.run = 'success';
return fn; return fn;
}) })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should apply allow undefined return', function() { it('should apply allow undefined return', function () {
expectTemplate('{{#helper}}{{*decorator}}suc{{/helper}}') expectTemplate('{{#helper}}{{*decorator}}suc{{/helper}}')
.withHelper('helper', function(options) { .withHelper('helper', function (options) {
return options.fn() + options.fn.run; return options.fn() + options.fn.run;
}) })
.withDecorator('decorator', function(fn) { .withDecorator('decorator', function (fn) {
fn.run = 'cess'; fn.run = 'cess';
}) })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should apply block decorators', function() { it('should apply block decorators', function () {
expectTemplate( expectTemplate(
'{{#helper}}{{#*decorator}}success{{/decorator}}{{/helper}}' '{{#helper}}{{#*decorator}}success{{/decorator}}{{/helper}}'
) )
.withHelper('helper', function(options) { .withHelper('helper', function (options) {
return options.fn.run; return options.fn.run;
}) })
.withDecorator('decorator', function(fn, props, container, options) { .withDecorator('decorator', function (fn, props, container, options) {
fn.run = options.fn(); fn.run = options.fn();
return fn; return fn;
}) })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should support nested decorators', function() { it('should support nested decorators', function () {
expectTemplate( expectTemplate(
'{{#helper}}{{#*decorator}}{{#*nested}}suc{{/nested}}cess{{/decorator}}{{/helper}}' '{{#helper}}{{#*decorator}}{{#*nested}}suc{{/nested}}cess{{/decorator}}{{/helper}}'
) )
.withHelper('helper', function(options) { .withHelper('helper', function (options) {
return options.fn.run; return options.fn.run;
}) })
.withDecorators({ .withDecorators({
decorator: function(fn, props, container, options) { decorator: function (fn, props, container, options) {
fn.run = options.fn.nested + options.fn(); fn.run = options.fn.nested + options.fn();
return fn; return fn;
}, },
nested: function(fn, props, container, options) { nested: function (fn, props, container, options) {
props.nested = options.fn(); props.nested = options.fn();
} },
}) })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should apply multiple decorators', function() { it('should apply multiple decorators', function () {
expectTemplate( expectTemplate(
'{{#helper}}{{#*decorator}}suc{{/decorator}}{{#*decorator}}cess{{/decorator}}{{/helper}}' '{{#helper}}{{#*decorator}}suc{{/decorator}}{{#*decorator}}cess{{/decorator}}{{/helper}}'
) )
.withHelper('helper', function(options) { .withHelper('helper', function (options) {
return options.fn.run; return options.fn.run;
}) })
.withDecorator('decorator', function(fn, props, container, options) { .withDecorator('decorator', function (fn, props, container, options) {
fn.run = (fn.run || '') + options.fn(); fn.run = (fn.run || '') + options.fn();
return fn; return fn;
}) })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should access parent variables', function() { it('should access parent variables', function () {
expectTemplate('{{#helper}}{{*decorator foo}}{{/helper}}') expectTemplate('{{#helper}}{{*decorator foo}}{{/helper}}')
.withHelper('helper', function(options) { .withHelper('helper', function (options) {
return options.fn.run; return options.fn.run;
}) })
.withDecorator('decorator', function(fn, props, container, options) { .withDecorator('decorator', function (fn, props, container, options) {
fn.run = options.args; fn.run = options.args;
return fn; return fn;
}) })
@@ -377,10 +377,10 @@ describe('blocks', function() {
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should work with root program', function() { it('should work with root program', function () {
var run; var run;
expectTemplate('{{*decorator "success"}}') expectTemplate('{{*decorator "success"}}')
.withDecorator('decorator', function(fn, props, container, options) { .withDecorator('decorator', function (fn, props, container, options) {
equals(options.args[0], 'success'); equals(options.args[0], 'success');
run = true; run = true;
return fn; return fn;
@@ -390,10 +390,10 @@ describe('blocks', function() {
equals(run, true); equals(run, true);
}); });
it('should fail when accessing variables from root', function() { it('should fail when accessing variables from root', function () {
var run; var run;
expectTemplate('{{*decorator foo}}') expectTemplate('{{*decorator foo}}')
.withDecorator('decorator', function(fn, props, container, options) { .withDecorator('decorator', function (fn, props, container, options) {
equals(options.args[0], undefined); equals(options.args[0], undefined);
run = true; run = true;
return fn; return fn;
@@ -403,11 +403,11 @@ describe('blocks', function() {
equals(run, true); equals(run, true);
}); });
describe('registration', function() { describe('registration', function () {
it('unregisters', function() { it('unregisters', function () {
handlebarsEnv.decorators = {}; handlebarsEnv.decorators = {};
handlebarsEnv.registerDecorator('foo', function() { handlebarsEnv.registerDecorator('foo', function () {
return 'fail'; return 'fail';
}); });
@@ -416,12 +416,12 @@ describe('blocks', function() {
equals(handlebarsEnv.decorators.foo, undefined); equals(handlebarsEnv.decorators.foo, undefined);
}); });
it('allows multiple globals', function() { it('allows multiple globals', function () {
handlebarsEnv.decorators = {}; handlebarsEnv.decorators = {};
handlebarsEnv.registerDecorator({ handlebarsEnv.registerDecorator({
foo: function() {}, foo: function () {},
bar: function() {} bar: function () {},
}); });
equals(!!handlebarsEnv.decorators.foo, true); equals(!!handlebarsEnv.decorators.foo, true);
@@ -432,17 +432,17 @@ describe('blocks', function() {
equals(handlebarsEnv.decorators.bar, undefined); equals(handlebarsEnv.decorators.bar, undefined);
}); });
it('fails with multiple and args', function() { it('fails with multiple and args', function () {
shouldThrow( shouldThrow(
function() { function () {
handlebarsEnv.registerDecorator( handlebarsEnv.registerDecorator(
{ {
world: function() { world: function () {
return 'world!'; return 'world!';
}, },
testHelper: function() { testHelper: function () {
return 'found it!'; return 'found it!';
} },
}, },
{} {}
); );
+128 -126
View File
@@ -1,12 +1,12 @@
describe('builtin helpers', function() { describe('builtin helpers', function () {
describe('#if', function() { describe('#if', function () {
it('if', function() { it('if', function () {
var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!'; var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!';
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: true, goodbye: true,
world: 'world' world: 'world',
}) })
.withMessage('if with boolean argument shows the contents when true') .withMessage('if with boolean argument shows the contents when true')
.toCompileTo('GOODBYE cruel world!'); .toCompileTo('GOODBYE cruel world!');
@@ -14,7 +14,7 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: 'dummy', goodbye: 'dummy',
world: 'world' world: 'world',
}) })
.withMessage('if with string argument shows the contents') .withMessage('if with string argument shows the contents')
.toCompileTo('GOODBYE cruel world!'); .toCompileTo('GOODBYE cruel world!');
@@ -22,7 +22,7 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: false, goodbye: false,
world: 'world' world: 'world',
}) })
.withMessage( .withMessage(
'if with boolean argument does not show the contents when false' 'if with boolean argument does not show the contents when false'
@@ -37,7 +37,7 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: ['foo'], goodbye: ['foo'],
world: 'world' world: 'world',
}) })
.withMessage('if with non-empty array shows the contents') .withMessage('if with non-empty array shows the contents')
.toCompileTo('GOODBYE cruel world!'); .toCompileTo('GOODBYE cruel world!');
@@ -45,7 +45,7 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: [], goodbye: [],
world: 'world' world: 'world',
}) })
.withMessage('if with empty array does not show the contents') .withMessage('if with empty array does not show the contents')
.toCompileTo('cruel world!'); .toCompileTo('cruel world!');
@@ -53,7 +53,7 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: 0, goodbye: 0,
world: 'world' world: 'world',
}) })
.withMessage('if with zero does not show the contents') .withMessage('if with zero does not show the contents')
.toCompileTo('cruel world!'); .toCompileTo('cruel world!');
@@ -63,21 +63,21 @@ describe('builtin helpers', function() {
) )
.withInput({ .withInput({
goodbye: 0, goodbye: 0,
world: 'world' world: 'world',
}) })
.withMessage('if with zero does not show the contents') .withMessage('if with zero does not show the contents')
.toCompileTo('GOODBYE cruel world!'); .toCompileTo('GOODBYE cruel world!');
}); });
it('if with function argument', function() { it('if with function argument', function () {
var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!'; var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!';
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: function() { goodbye: function () {
return true; return true;
}, },
world: 'world' world: 'world',
}) })
.withMessage( .withMessage(
'if with function shows the contents when function returns true' 'if with function shows the contents when function returns true'
@@ -86,10 +86,10 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: function() { goodbye: function () {
return this.world; return this.world;
}, },
world: 'world' world: 'world',
}) })
.withMessage( .withMessage(
'if with function shows the contents when function returns string' 'if with function shows the contents when function returns string'
@@ -98,10 +98,10 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: function() { goodbye: function () {
return false; return false;
}, },
world: 'world' world: 'world',
}) })
.withMessage( .withMessage(
'if with function does not show the contents when returns false' 'if with function does not show the contents when returns false'
@@ -110,10 +110,10 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbye: function() { goodbye: function () {
return this.foo; return this.foo;
}, },
world: 'world' world: 'world',
}) })
.withMessage( .withMessage(
'if with function does not show the contents when returns undefined' 'if with function does not show the contents when returns undefined'
@@ -121,61 +121,61 @@ describe('builtin helpers', function() {
.toCompileTo('cruel world!'); .toCompileTo('cruel world!');
}); });
it('should not change the depth list', function() { it('should not change the depth list', function () {
expectTemplate( expectTemplate(
'{{#with foo}}{{#if goodbye}}GOODBYE cruel {{../world}}!{{/if}}{{/with}}' '{{#with foo}}{{#if goodbye}}GOODBYE cruel {{../world}}!{{/if}}{{/with}}'
) )
.withInput({ .withInput({
foo: { goodbye: true }, foo: { goodbye: true },
world: 'world' world: 'world',
}) })
.toCompileTo('GOODBYE cruel world!'); .toCompileTo('GOODBYE cruel world!');
}); });
}); });
describe('#with', function() { describe('#with', function () {
it('with', function() { it('with', function () {
expectTemplate('{{#with person}}{{first}} {{last}}{{/with}}') expectTemplate('{{#with person}}{{first}} {{last}}{{/with}}')
.withInput({ .withInput({
person: { person: {
first: 'Alan', first: 'Alan',
last: 'Johnson' last: 'Johnson',
} },
}) })
.toCompileTo('Alan Johnson'); .toCompileTo('Alan Johnson');
}); });
it('with with function argument', function() { it('with with function argument', function () {
expectTemplate('{{#with person}}{{first}} {{last}}{{/with}}') expectTemplate('{{#with person}}{{first}} {{last}}{{/with}}')
.withInput({ .withInput({
person: function() { person: function () {
return { return {
first: 'Alan', first: 'Alan',
last: 'Johnson' last: 'Johnson',
}; };
} },
}) })
.toCompileTo('Alan Johnson'); .toCompileTo('Alan Johnson');
}); });
it('with with else', function() { it('with with else', function () {
expectTemplate( expectTemplate(
'{{#with person}}Person is present{{else}}Person is not present{{/with}}' '{{#with person}}Person is present{{else}}Person is not present{{/with}}'
).toCompileTo('Person is not present'); ).toCompileTo('Person is not present');
}); });
it('with provides block parameter', function() { it('with provides block parameter', function () {
expectTemplate('{{#with person as |foo|}}{{foo.first}} {{last}}{{/with}}') expectTemplate('{{#with person as |foo|}}{{foo.first}} {{last}}{{/with}}')
.withInput({ .withInput({
person: { person: {
first: 'Alan', first: 'Alan',
last: 'Johnson' last: 'Johnson',
} },
}) })
.toCompileTo('Alan Johnson'); .toCompileTo('Alan Johnson');
}); });
it('works when data is disabled', function() { it('works when data is disabled', function () {
expectTemplate('{{#with person as |foo|}}{{foo.first}} {{last}}{{/with}}') expectTemplate('{{#with person as |foo|}}{{foo.first}} {{last}}{{/with}}')
.withInput({ person: { first: 'Alan', last: 'Johnson' } }) .withInput({ person: { first: 'Alan', last: 'Johnson' } })
.withCompileOptions({ data: false }) .withCompileOptions({ data: false })
@@ -183,14 +183,14 @@ describe('builtin helpers', function() {
}); });
}); });
describe('#each', function() { describe('#each', function () {
beforeEach(function() { beforeEach(function () {
handlebarsEnv.registerHelper('detectDataInsideEach', function(options) { handlebarsEnv.registerHelper('detectDataInsideEach', function (options) {
return options.data && options.data.exclaim; return options.data && options.data.exclaim;
}); });
}); });
it('each', function() { it('each', function () {
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
expectTemplate(string) expectTemplate(string)
@@ -198,9 +198,9 @@ describe('builtin helpers', function() {
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withMessage( .withMessage(
'each with array argument iterates over the contents when not empty' 'each with array argument iterates over the contents when not empty'
@@ -210,21 +210,21 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbyes: [], goodbyes: [],
world: 'world' world: 'world',
}) })
.withMessage('each with array argument ignores the contents when empty') .withMessage('each with array argument ignores the contents when empty')
.toCompileTo('cruel world!'); .toCompileTo('cruel world!');
}); });
it('each without data', function() { it('each without data', function () {
expectTemplate('{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!') expectTemplate('{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!')
.withInput({ .withInput({
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withRuntimeOptions({ data: false }) .withRuntimeOptions({ data: false })
.withCompileOptions({ data: false }) .withCompileOptions({ data: false })
@@ -237,13 +237,13 @@ describe('builtin helpers', function() {
.toCompileTo('cruelworld'); .toCompileTo('cruelworld');
}); });
it('each without context', function() { it('each without context', function () {
expectTemplate('{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!') expectTemplate('{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!')
.withInput(undefined) .withInput(undefined)
.toCompileTo('cruel !'); .toCompileTo('cruel !');
}); });
it('each with an object and @key', function() { it('each with an object and @key', function () {
var string = var string =
'{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!'; '{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!';
@@ -272,12 +272,12 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbyes: {}, goodbyes: {},
world: 'world' world: 'world',
}) })
.toCompileTo('cruel world!'); .toCompileTo('cruel world!');
}); });
it('each with @index', function() { it('each with @index', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!' '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!'
) )
@@ -285,15 +285,15 @@ describe('builtin helpers', function() {
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withMessage('The @index variable is used') .withMessage('The @index variable is used')
.toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!'); .toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!');
}); });
it('each with nested @index', function() { it('each with nested @index', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}cruel {{world}}!' '{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}cruel {{world}}!'
) )
@@ -301,9 +301,9 @@ describe('builtin helpers', function() {
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withMessage('The @index variable is used') .withMessage('The @index variable is used')
.toCompileTo( .toCompileTo(
@@ -311,20 +311,20 @@ describe('builtin helpers', function() {
); );
}); });
it('each with block params', function() { it('each with block params', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes as |value index|}}{{index}}. {{value.text}}! {{#each ../goodbyes as |childValue childIndex|}} {{index}} {{childIndex}}{{/each}} After {{index}} {{/each}}{{index}}cruel {{world}}!' '{{#each goodbyes as |value index|}}{{index}}. {{value.text}}! {{#each ../goodbyes as |childValue childIndex|}} {{index}} {{childIndex}}{{/each}} After {{index}} {{/each}}{{index}}cruel {{world}}!'
) )
.withInput({ .withInput({
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }], goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }],
world: 'world' world: 'world',
}) })
.toCompileTo( .toCompileTo(
'0. goodbye! 0 0 0 1 After 0 1. Goodbye! 1 0 1 1 After 1 cruel world!' '0. goodbye! 0 0 0 1 After 0 1. Goodbye! 1 0 1 1 After 1 cruel world!'
); );
}); });
it('each with block params and strict compilation', function() { it('each with block params and strict compilation', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes as |value index|}}{{index}}. {{value.text}}!{{/each}}' '{{#each goodbyes as |value index|}}{{index}}. {{value.text}}!{{/each}}'
) )
@@ -333,7 +333,7 @@ describe('builtin helpers', function() {
.toCompileTo('0. goodbye!1. Goodbye!'); .toCompileTo('0. goodbye!1. Goodbye!');
}); });
it('each object with @index', function() { it('each object with @index', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!' '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!'
) )
@@ -341,15 +341,15 @@ describe('builtin helpers', function() {
goodbyes: { goodbyes: {
a: { text: 'goodbye' }, a: { text: 'goodbye' },
b: { text: 'Goodbye' }, b: { text: 'Goodbye' },
c: { text: 'GOODBYE' } c: { text: 'GOODBYE' },
}, },
world: 'world' world: 'world',
}) })
.withMessage('The @index variable is used') .withMessage('The @index variable is used')
.toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!'); .toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!');
}); });
it('each with @first', function() { it('each with @first', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!' '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!'
) )
@@ -357,15 +357,15 @@ describe('builtin helpers', function() {
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withMessage('The @first variable is used') .withMessage('The @first variable is used')
.toCompileTo('goodbye! cruel world!'); .toCompileTo('goodbye! cruel world!');
}); });
it('each with nested @first', function() { it('each with nested @first', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!' '{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!'
) )
@@ -373,9 +373,9 @@ describe('builtin helpers', function() {
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withMessage('The @first variable is used') .withMessage('The @first variable is used')
.toCompileTo( .toCompileTo(
@@ -383,19 +383,19 @@ describe('builtin helpers', function() {
); );
}); });
it('each object with @first', function() { it('each object with @first', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!' '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!'
) )
.withInput({ .withInput({
goodbyes: { foo: { text: 'goodbye' }, bar: { text: 'Goodbye' } }, goodbyes: { foo: { text: 'goodbye' }, bar: { text: 'Goodbye' } },
world: 'world' world: 'world',
}) })
.withMessage('The @first variable is used') .withMessage('The @first variable is used')
.toCompileTo('goodbye! cruel world!'); .toCompileTo('goodbye! cruel world!');
}); });
it('each with @last', function() { it('each with @last', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!' '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!'
) )
@@ -403,27 +403,27 @@ describe('builtin helpers', function() {
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withMessage('The @last variable is used') .withMessage('The @last variable is used')
.toCompileTo('GOODBYE! cruel world!'); .toCompileTo('GOODBYE! cruel world!');
}); });
it('each object with @last', function() { it('each object with @last', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!' '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!'
) )
.withInput({ .withInput({
goodbyes: { foo: { text: 'goodbye' }, bar: { text: 'Goodbye' } }, goodbyes: { foo: { text: 'goodbye' }, bar: { text: 'Goodbye' } },
world: 'world' world: 'world',
}) })
.withMessage('The @last variable is used') .withMessage('The @last variable is used')
.toCompileTo('Goodbye! cruel world!'); .toCompileTo('Goodbye! cruel world!');
}); });
it('each with nested @last', function() { it('each with nested @last', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!' '{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!'
) )
@@ -431,9 +431,9 @@ describe('builtin helpers', function() {
goodbyes: [ goodbyes: [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
], ],
world: 'world' world: 'world',
}) })
.withMessage('The @last variable is used') .withMessage('The @last variable is used')
.toCompileTo( .toCompileTo(
@@ -441,19 +441,19 @@ describe('builtin helpers', function() {
); );
}); });
it('each with function argument', function() { it('each with function argument', function () {
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbyes: function() { goodbyes: function () {
return [ return [
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
]; ];
}, },
world: 'world' world: 'world',
}) })
.withMessage( .withMessage(
'each with array function argument iterates over the contents when not empty' 'each with array function argument iterates over the contents when not empty'
@@ -463,7 +463,7 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbyes: [], goodbyes: [],
world: 'world' world: 'world',
}) })
.withMessage( .withMessage(
'each with array function argument ignores the contents when empty' 'each with array function argument ignores the contents when empty'
@@ -471,7 +471,7 @@ describe('builtin helpers', function() {
.toCompileTo('cruel world!'); .toCompileTo('cruel world!');
}); });
it('each object when last key is an empty string', function() { it('each object when last key is an empty string', function () {
expectTemplate( expectTemplate(
'{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!' '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!'
) )
@@ -479,15 +479,15 @@ describe('builtin helpers', function() {
goodbyes: { goodbyes: {
a: { text: 'goodbye' }, a: { text: 'goodbye' },
b: { text: 'Goodbye' }, b: { text: 'Goodbye' },
'': { text: 'GOODBYE' } '': { text: 'GOODBYE' },
}, },
world: 'world' world: 'world',
}) })
.withMessage('Empty string key is not skipped') .withMessage('Empty string key is not skipped')
.toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!'); .toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!');
}); });
it('data passed to helpers', function() { it('data passed to helpers', function () {
expectTemplate( expectTemplate(
'{{#each letters}}{{this}}{{detectDataInsideEach}}{{/each}}' '{{#each letters}}{{this}}{{detectDataInsideEach}}{{/each}}'
) )
@@ -495,13 +495,13 @@ describe('builtin helpers', function() {
.withMessage('should output data') .withMessage('should output data')
.withRuntimeOptions({ .withRuntimeOptions({
data: { data: {
exclaim: '!' exclaim: '!',
} },
}) })
.toCompileTo('a!b!c!'); .toCompileTo('a!b!c!');
}); });
it('each on implicit context', function() { it('each on implicit context', function () {
expectTemplate('{{#each}}{{text}}! {{/each}}cruel world!').toThrow( expectTemplate('{{#each}}{{text}}! {{/each}}cruel world!').toThrow(
handlebarsEnv.Exception, handlebarsEnv.Exception,
'Must pass iterator to #each' 'Must pass iterator to #each'
@@ -509,12 +509,12 @@ describe('builtin helpers', function() {
}); });
if (global.Symbol && global.Symbol.iterator) { if (global.Symbol && global.Symbol.iterator) {
it('each on iterable', function() { it('each on iterable', function () {
function Iterator(arr) { function Iterator(arr) {
this.arr = arr; this.arr = arr;
this.index = 0; this.index = 0;
} }
Iterator.prototype.next = function() { Iterator.prototype.next = function () {
var value = this.arr[this.index]; var value = this.arr[this.index];
var done = this.index === this.arr.length; var done = this.index === this.arr.length;
if (!done) { if (!done) {
@@ -525,7 +525,7 @@ describe('builtin helpers', function() {
function Iterable(arr) { function Iterable(arr) {
this.arr = arr; this.arr = arr;
} }
Iterable.prototype[global.Symbol.iterator] = function() { Iterable.prototype[global.Symbol.iterator] = function () {
return new Iterator(this.arr); return new Iterator(this.arr);
}; };
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
@@ -535,9 +535,9 @@ describe('builtin helpers', function() {
goodbyes: new Iterable([ goodbyes: new Iterable([
{ text: 'goodbye' }, { text: 'goodbye' },
{ text: 'Goodbye' }, { text: 'Goodbye' },
{ text: 'GOODBYE' } { text: 'GOODBYE' },
]), ]),
world: 'world' world: 'world',
}) })
.withMessage( .withMessage(
'each with array argument iterates over the contents when not empty' 'each with array argument iterates over the contents when not empty'
@@ -547,7 +547,7 @@ describe('builtin helpers', function() {
expectTemplate(string) expectTemplate(string)
.withInput({ .withInput({
goodbyes: new Iterable([]), goodbyes: new Iterable([]),
world: 'world' world: 'world',
}) })
.withMessage( .withMessage(
'each with array argument ignores the contents when empty' 'each with array argument ignores the contents when empty'
@@ -557,27 +557,27 @@ describe('builtin helpers', function() {
} }
}); });
describe('#log', function() { describe('#log', function () {
/* eslint-disable no-console */ /* eslint-disable no-console */
if (typeof console === 'undefined') { if (typeof console === 'undefined') {
return; return;
} }
var $log, $info, $error; var $log, $info, $error;
beforeEach(function() { beforeEach(function () {
$log = console.log; $log = console.log;
$info = console.info; $info = console.info;
$error = console.error; $error = console.error;
}); });
afterEach(function() { afterEach(function () {
console.log = $log; console.log = $log;
console.info = $info; console.info = $info;
console.error = $error; console.error = $error;
}); });
it('should call logger at default level', function() { it('should call logger at default level', function () {
var levelArg, logArg; var levelArg, logArg;
handlebarsEnv.log = function(level, arg) { handlebarsEnv.log = function (level, arg) {
levelArg = level; levelArg = level;
logArg = arg; logArg = arg;
}; };
@@ -590,9 +590,9 @@ describe('builtin helpers', function() {
equals('whee', logArg, "should call log with 'whee'"); equals('whee', logArg, "should call log with 'whee'");
}); });
it('should call logger at data level', function() { it('should call logger at data level', function () {
var levelArg, logArg; var levelArg, logArg;
handlebarsEnv.log = function(level, arg) { handlebarsEnv.log = function (level, arg) {
levelArg = level; levelArg = level;
logArg = arg; logArg = arg;
}; };
@@ -606,16 +606,16 @@ describe('builtin helpers', function() {
equals('whee', logArg); equals('whee', logArg);
}); });
it('should output to info', function() { it('should output to info', function () {
var called; var called;
console.info = function(info) { console.info = function (info) {
equals('whee', info); equals('whee', info);
called = true; called = true;
console.info = $info; console.info = $info;
console.log = $log; console.log = $log;
}; };
console.log = function(log) { console.log = function (log) {
equals('whee', log); equals('whee', log);
called = true; called = true;
console.info = $info; console.info = $info;
@@ -628,10 +628,10 @@ describe('builtin helpers', function() {
equals(true, called); equals(true, called);
}); });
it('should log at data level', function() { it('should log at data level', function () {
var called; var called;
console.error = function(log) { console.error = function (log) {
equals('whee', log); equals('whee', log);
called = true; called = true;
console.error = $error; console.error = $error;
@@ -645,11 +645,11 @@ describe('builtin helpers', function() {
equals(true, called); equals(true, called);
}); });
it('should handle missing logger', function() { it('should handle missing logger', function () {
var called = false; var called = false;
console.error = undefined; console.error = undefined;
console.log = function(log) { console.log = function (log) {
equals('whee', log); equals('whee', log);
called = true; called = true;
console.log = $log; console.log = $log;
@@ -663,10 +663,10 @@ describe('builtin helpers', function() {
equals(true, called); equals(true, called);
}); });
it('should handle string log levels', function() { it('should handle string log levels', function () {
var called; var called;
console.error = function(log) { console.error = function (log) {
equals('whee', log); equals('whee', log);
called = true; called = true;
}; };
@@ -688,10 +688,10 @@ describe('builtin helpers', function() {
equals(true, called); equals(true, called);
}); });
it('should handle hash log levels', function() { it('should handle hash log levels', function () {
var called; var called;
console.error = function(log) { console.error = function (log) {
equals('whee', log); equals('whee', log);
called = true; called = true;
}; };
@@ -702,13 +702,17 @@ describe('builtin helpers', function() {
equals(true, called); equals(true, called);
}); });
it('should handle hash log levels', function() { it('should handle hash log levels', function () {
var called = false; var called = false;
console.info = console.log = console.error = console.debug = function() { console.info =
called = true; console.log =
console.info = console.log = console.error = console.debug = $log; console.error =
}; console.debug =
function () {
called = true;
console.info = console.log = console.error = console.debug = $log;
};
expectTemplate('{{log blah level="debug"}}') expectTemplate('{{log blah level="debug"}}')
.withInput({ blah: 'whee' }) .withInput({ blah: 'whee' })
@@ -716,10 +720,10 @@ describe('builtin helpers', function() {
equals(false, called); equals(false, called);
}); });
it('should pass multiple log arguments', function() { it('should pass multiple log arguments', function () {
var called; var called;
console.info = console.log = function(log1, log2, log3) { console.info = console.log = function (log1, log2, log3) {
equals('whee', log1); equals('whee', log1);
equals('foo', log2); equals('foo', log2);
equals(1, log3); equals(1, log3);
@@ -733,31 +737,29 @@ describe('builtin helpers', function() {
equals(true, called); equals(true, called);
}); });
it('should pass zero log arguments', function() { it('should pass zero log arguments', function () {
var called; var called;
console.info = console.log = function() { console.info = console.log = function () {
expect(arguments.length).to.equal(0); expect(arguments.length).to.equal(0);
called = true; called = true;
console.log = $log; console.log = $log;
}; };
expectTemplate('{{log}}') expectTemplate('{{log}}').withInput({ blah: 'whee' }).toCompileTo('');
.withInput({ blah: 'whee' })
.toCompileTo('');
expect(called).to.be.true(); expect(called).to.be.true();
}); });
/* eslint-enable no-console */ /* eslint-enable no-console */
}); });
describe('#lookup', function() { describe('#lookup', function () {
it('should lookup arbitrary content', function() { it('should lookup arbitrary content', function () {
expectTemplate('{{#each goodbyes}}{{lookup ../data .}}{{/each}}') expectTemplate('{{#each goodbyes}}{{lookup ../data .}}{{/each}}')
.withInput({ goodbyes: [0, 1], data: ['foo', 'bar'] }) .withInput({ goodbyes: [0, 1], data: ['foo', 'bar'] })
.toCompileTo('foobar'); .toCompileTo('foobar');
}); });
it('should not fail on undefined value', function() { it('should not fail on undefined value', function () {
expectTemplate('{{#each goodbyes}}{{lookup ../bar .}}{{/each}}') expectTemplate('{{#each goodbyes}}{{lookup ../bar .}}{{/each}}')
.withInput({ goodbyes: [0, 1], data: ['foo', 'bar'] }) .withInput({ goodbyes: [0, 1], data: ['foo', 'bar'] })
.toCompileTo(''); .toCompileTo('');
+25 -25
View File
@@ -1,15 +1,15 @@
describe('compiler', function() { describe('compiler', function () {
if (!Handlebars.compile) { if (!Handlebars.compile) {
return; return;
} }
describe('#equals', function() { describe('#equals', function () {
function compile(string) { function compile(string) {
var ast = Handlebars.parse(string); var ast = Handlebars.parse(string);
return new Handlebars.Compiler().compile(ast, {}); return new Handlebars.Compiler().compile(ast, {});
} }
it('should treat as equal', function() { it('should treat as equal', function () {
equal(compile('foo').equals(compile('foo')), true); equal(compile('foo').equals(compile('foo')), true);
equal(compile('{{foo}}').equals(compile('{{foo}}')), true); equal(compile('{{foo}}').equals(compile('{{foo}}')), true);
equal(compile('{{foo.bar}}').equals(compile('{{foo.bar}}')), true); equal(compile('{{foo.bar}}').equals(compile('{{foo.bar}}')), true);
@@ -30,7 +30,7 @@ describe('compiler', function() {
true true
); );
}); });
it('should treat as not equal', function() { it('should treat as not equal', function () {
equal(compile('foo').equals(compile('bar')), false); equal(compile('foo').equals(compile('bar')), false);
equal(compile('{{foo}}').equals(compile('{{bar}}')), false); equal(compile('{{foo}}').equals(compile('{{bar}}')), false);
equal(compile('{{foo.bar}}').equals(compile('{{bar.bar}}')), false); equal(compile('{{foo.bar}}').equals(compile('{{bar.bar}}')), false);
@@ -59,17 +59,17 @@ describe('compiler', function() {
}); });
}); });
describe('#compile', function() { describe('#compile', function () {
it('should fail with invalid input', function() { it('should fail with invalid input', function () {
shouldThrow( shouldThrow(
function() { function () {
Handlebars.compile(null); Handlebars.compile(null);
}, },
Error, Error,
'You must pass a string or Handlebars AST to Handlebars.compile. You passed null' 'You must pass a string or Handlebars AST to Handlebars.compile. You passed null'
); );
shouldThrow( shouldThrow(
function() { function () {
Handlebars.compile({}); Handlebars.compile({});
}, },
Error, Error,
@@ -77,7 +77,7 @@ describe('compiler', function() {
); );
}); });
it('should include the location in the error (row and column)', function() { it('should include the location in the error (row and column)', function () {
try { try {
Handlebars.compile(' \n {{#if}}\n{{/def}}')(); Handlebars.compile(' \n {{#if}}\n{{/def}}')();
equal( equal(
@@ -101,7 +101,7 @@ describe('compiler', function() {
} }
}); });
it('should include the location as enumerable property', function() { it('should include the location as enumerable property', function () {
try { try {
Handlebars.compile(' \n {{#if}}\n{{/def}}')(); Handlebars.compile(' \n {{#if}}\n{{/def}}')();
equal( equal(
@@ -118,30 +118,30 @@ describe('compiler', function() {
} }
}); });
it('can utilize AST instance', function() { it('can utilize AST instance', function () {
equal( equal(
Handlebars.compile({ Handlebars.compile({
type: 'Program', type: 'Program',
body: [{ type: 'ContentStatement', value: 'Hello' }] body: [{ type: 'ContentStatement', value: 'Hello' }],
})(), })(),
'Hello' 'Hello'
); );
}); });
it('can pass through an empty string', function() { it('can pass through an empty string', function () {
equal(Handlebars.compile('')(), ''); equal(Handlebars.compile('')(), '');
}); });
it('throws on desupported options', function() { it('throws on desupported options', function () {
shouldThrow( shouldThrow(
function() { function () {
Handlebars.compile('Dudes', { trackIds: true }); Handlebars.compile('Dudes', { trackIds: true });
}, },
Error, Error,
'TrackIds and stringParams are no longer supported. See Github #1145' 'TrackIds and stringParams are no longer supported. See Github #1145'
); );
shouldThrow( shouldThrow(
function() { function () {
Handlebars.compile('Dudes', { stringParams: true }); Handlebars.compile('Dudes', { stringParams: true });
}, },
Error, Error,
@@ -149,7 +149,7 @@ describe('compiler', function() {
); );
}); });
it('should not modify the options.data property(GH-1327)', function() { it('should not modify the options.data property(GH-1327)', function () {
var options = { data: [{ a: 'foo' }, { a: 'bar' }] }; var options = { data: [{ a: 'foo' }, { a: 'bar' }] };
Handlebars.compile('{{#each data}}{{@index}}:{{a}} {{/each}}', options)(); Handlebars.compile('{{#each data}}{{@index}}:{{a}} {{/each}}', options)();
equal( equal(
@@ -158,7 +158,7 @@ describe('compiler', function() {
); );
}); });
it('should not modify the options.knownHelpers property(GH-1327)', function() { it('should not modify the options.knownHelpers property(GH-1327)', function () {
var options = { knownHelpers: {} }; var options = { knownHelpers: {} };
Handlebars.compile('{{#each data}}{{@index}}:{{a}} {{/each}}', options)(); Handlebars.compile('{{#each data}}{{@index}}:{{a}} {{/each}}', options)();
equal( equal(
@@ -168,17 +168,17 @@ describe('compiler', function() {
}); });
}); });
describe('#precompile', function() { describe('#precompile', function () {
it('should fail with invalid input', function() { it('should fail with invalid input', function () {
shouldThrow( shouldThrow(
function() { function () {
Handlebars.precompile(null); Handlebars.precompile(null);
}, },
Error, Error,
'You must pass a string or Handlebars AST to Handlebars.compile. You passed null' 'You must pass a string or Handlebars AST to Handlebars.compile. You passed null'
); );
shouldThrow( shouldThrow(
function() { function () {
Handlebars.precompile({}); Handlebars.precompile({});
}, },
Error, Error,
@@ -186,19 +186,19 @@ describe('compiler', function() {
); );
}); });
it('can utilize AST instance', function() { it('can utilize AST instance', function () {
equal( equal(
/return "Hello"/.test( /return "Hello"/.test(
Handlebars.precompile({ Handlebars.precompile({
type: 'Program', type: 'Program',
body: [{ type: 'ContentStatement', value: 'Hello' }] body: [{ type: 'ContentStatement', value: 'Hello' }],
}) })
), ),
true true
); );
}); });
it('can pass through an empty string', function() { it('can pass through an empty string', function () {
equal(/return ""/.test(Handlebars.precompile('')), true); equal(/return ""/.test(Handlebars.precompile('')), true);
}); });
}); });
+53 -53
View File
@@ -1,8 +1,8 @@
describe('data', function() { describe('data', function () {
it('passing in data to a compiled function that expects data - works with helpers', function() { it('passing in data to a compiled function that expects data - works with helpers', function () {
expectTemplate('{{hello}}') expectTemplate('{{hello}}')
.withCompileOptions({ data: true }) .withCompileOptions({ data: true })
.withHelper('hello', function(options) { .withHelper('hello', function (options) {
return options.data.adjective + ' ' + this.noun; return options.data.adjective + ' ' + this.noun;
}) })
.withRuntimeOptions({ data: { adjective: 'happy' } }) .withRuntimeOptions({ data: { adjective: 'happy' } })
@@ -11,17 +11,17 @@ describe('data', function() {
.toCompileTo('happy cat'); .toCompileTo('happy cat');
}); });
it('data can be looked up via @foo', function() { it('data can be looked up via @foo', function () {
expectTemplate('{{@hello}}') expectTemplate('{{@hello}}')
.withRuntimeOptions({ data: { hello: 'hello' } }) .withRuntimeOptions({ data: { hello: 'hello' } })
.withMessage('@foo retrieves template data') .withMessage('@foo retrieves template data')
.toCompileTo('hello'); .toCompileTo('hello');
}); });
it('deep @foo triggers automatic top-level data', function() { it('deep @foo triggers automatic top-level data', function () {
var helpers = Handlebars.createFrame(handlebarsEnv.helpers); var helpers = Handlebars.createFrame(handlebarsEnv.helpers);
helpers.let = function(options) { helpers.let = function (options) {
var frame = Handlebars.createFrame(options.data); var frame = Handlebars.createFrame(options.data);
for (var prop in options.hash) { for (var prop in options.hash) {
@@ -41,83 +41,83 @@ describe('data', function() {
.toCompileTo('Hello world'); .toCompileTo('Hello world');
}); });
it('parameter data can be looked up via @foo', function() { it('parameter data can be looked up via @foo', function () {
expectTemplate('{{hello @world}}') expectTemplate('{{hello @world}}')
.withRuntimeOptions({ data: { world: 'world' } }) .withRuntimeOptions({ data: { world: 'world' } })
.withHelper('hello', function(noun) { .withHelper('hello', function (noun) {
return 'Hello ' + noun; return 'Hello ' + noun;
}) })
.withMessage('@foo as a parameter retrieves template data') .withMessage('@foo as a parameter retrieves template data')
.toCompileTo('Hello world'); .toCompileTo('Hello world');
}); });
it('hash values can be looked up via @foo', function() { it('hash values can be looked up via @foo', function () {
expectTemplate('{{hello noun=@world}}') expectTemplate('{{hello noun=@world}}')
.withRuntimeOptions({ data: { world: 'world' } }) .withRuntimeOptions({ data: { world: 'world' } })
.withHelper('hello', function(options) { .withHelper('hello', function (options) {
return 'Hello ' + options.hash.noun; return 'Hello ' + options.hash.noun;
}) })
.withMessage('@foo as a parameter retrieves template data') .withMessage('@foo as a parameter retrieves template data')
.toCompileTo('Hello world'); .toCompileTo('Hello world');
}); });
it('nested parameter data can be looked up via @foo.bar', function() { it('nested parameter data can be looked up via @foo.bar', function () {
expectTemplate('{{hello @world.bar}}') expectTemplate('{{hello @world.bar}}')
.withRuntimeOptions({ data: { world: { bar: 'world' } } }) .withRuntimeOptions({ data: { world: { bar: 'world' } } })
.withHelper('hello', function(noun) { .withHelper('hello', function (noun) {
return 'Hello ' + noun; return 'Hello ' + noun;
}) })
.withMessage('@foo as a parameter retrieves template data') .withMessage('@foo as a parameter retrieves template data')
.toCompileTo('Hello world'); .toCompileTo('Hello world');
}); });
it('nested parameter data does not fail with @world.bar', function() { it('nested parameter data does not fail with @world.bar', function () {
expectTemplate('{{hello @world.bar}}') expectTemplate('{{hello @world.bar}}')
.withRuntimeOptions({ data: { foo: { bar: 'world' } } }) .withRuntimeOptions({ data: { foo: { bar: 'world' } } })
.withHelper('hello', function(noun) { .withHelper('hello', function (noun) {
return 'Hello ' + noun; return 'Hello ' + noun;
}) })
.withMessage('@foo as a parameter retrieves template data') .withMessage('@foo as a parameter retrieves template data')
.toCompileTo('Hello undefined'); .toCompileTo('Hello undefined');
}); });
it('parameter data throws when using complex scope references', function() { it('parameter data throws when using complex scope references', function () {
expectTemplate( expectTemplate(
'{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}' '{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}'
).toThrow(Error); ).toThrow(Error);
}); });
it('data can be functions', function() { it('data can be functions', function () {
expectTemplate('{{@hello}}') expectTemplate('{{@hello}}')
.withRuntimeOptions({ .withRuntimeOptions({
data: { data: {
hello: function() { hello: function () {
return 'hello'; return 'hello';
} },
} },
}) })
.toCompileTo('hello'); .toCompileTo('hello');
}); });
it('data can be functions with params', function() { it('data can be functions with params', function () {
expectTemplate('{{@hello "hello"}}') expectTemplate('{{@hello "hello"}}')
.withRuntimeOptions({ .withRuntimeOptions({
data: { data: {
hello: function(arg) { hello: function (arg) {
return arg; return arg;
} },
} },
}) })
.toCompileTo('hello'); .toCompileTo('hello');
}); });
it('data is inherited downstream', function() { it('data is inherited downstream', function () {
expectTemplate( expectTemplate(
'{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}' '{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}'
) )
.withInput({ bar: { baz: 'hello world' } }) .withInput({ bar: { baz: 'hello world' } })
.withCompileOptions({ data: true }) .withCompileOptions({ data: true })
.withHelper('let', function(options) { .withHelper('let', function (options) {
var frame = Handlebars.createFrame(options.data); var frame = Handlebars.createFrame(options.data);
for (var prop in options.hash) { for (var prop in options.hash) {
if (prop in options.hash) { if (prop in options.hash) {
@@ -131,11 +131,11 @@ describe('data', function() {
.toCompileTo('2hello world1'); .toCompileTo('2hello world1');
}); });
it('passing in data to a compiled function that expects data - works with helpers in partials', function() { it('passing in data to a compiled function that expects data - works with helpers in partials', function () {
expectTemplate('{{>myPartial}}') expectTemplate('{{>myPartial}}')
.withCompileOptions({ data: true }) .withCompileOptions({ data: true })
.withPartial('myPartial', '{{hello}}') .withPartial('myPartial', '{{hello}}')
.withHelper('hello', function(options) { .withHelper('hello', function (options) {
return options.data.adjective + ' ' + this.noun; return options.data.adjective + ' ' + this.noun;
}) })
.withInput({ noun: 'cat' }) .withInput({ noun: 'cat' })
@@ -144,10 +144,10 @@ describe('data', function() {
.toCompileTo('happy cat'); .toCompileTo('happy cat');
}); });
it('passing in data to a compiled function that expects data - works with helpers and parameters', function() { it('passing in data to a compiled function that expects data - works with helpers and parameters', function () {
expectTemplate('{{hello world}}') expectTemplate('{{hello world}}')
.withCompileOptions({ data: true }) .withCompileOptions({ data: true })
.withHelper('hello', function(noun, options) { .withHelper('hello', function (noun, options) {
return options.data.adjective + ' ' + noun + (this.exclaim ? '!' : ''); return options.data.adjective + ' ' + noun + (this.exclaim ? '!' : '');
}) })
.withInput({ exclaim: true, world: 'world' }) .withInput({ exclaim: true, world: 'world' })
@@ -156,15 +156,15 @@ describe('data', function() {
.toCompileTo('happy world!'); .toCompileTo('happy world!');
}); });
it('passing in data to a compiled function that expects data - works with block helpers', function() { it('passing in data to a compiled function that expects data - works with block helpers', function () {
expectTemplate('{{#hello}}{{world}}{{/hello}}') expectTemplate('{{#hello}}{{world}}{{/hello}}')
.withCompileOptions({ .withCompileOptions({
data: true data: true,
}) })
.withHelper('hello', function(options) { .withHelper('hello', function (options) {
return options.fn(this); return options.fn(this);
}) })
.withHelper('world', function(options) { .withHelper('world', function (options) {
return options.data.adjective + ' world' + (this.exclaim ? '!' : ''); return options.data.adjective + ' world' + (this.exclaim ? '!' : '');
}) })
.withInput({ exclaim: true }) .withInput({ exclaim: true })
@@ -173,13 +173,13 @@ describe('data', function() {
.toCompileTo('happy world!'); .toCompileTo('happy world!');
}); });
it('passing in data to a compiled function that expects data - works with block helpers that use ..', function() { it('passing in data to a compiled function that expects data - works with block helpers that use ..', function () {
expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}') expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}')
.withCompileOptions({ data: true }) .withCompileOptions({ data: true })
.withHelper('hello', function(options) { .withHelper('hello', function (options) {
return options.fn({ exclaim: '?' }); return options.fn({ exclaim: '?' });
}) })
.withHelper('world', function(thing, options) { .withHelper('world', function (thing, options) {
return options.data.adjective + ' ' + thing + (this.exclaim || ''); return options.data.adjective + ' ' + thing + (this.exclaim || '');
}) })
.withInput({ exclaim: true, zomg: 'world' }) .withInput({ exclaim: true, zomg: 'world' })
@@ -188,13 +188,13 @@ describe('data', function() {
.toCompileTo('happy world?'); .toCompileTo('happy world?');
}); });
it('passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..', function() { it('passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..', function () {
expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}') expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}')
.withCompileOptions({ data: true }) .withCompileOptions({ data: true })
.withHelper('hello', function(options) { .withHelper('hello', function (options) {
return options.data.accessData + ' ' + options.fn({ exclaim: '?' }); return options.data.accessData + ' ' + options.fn({ exclaim: '?' });
}) })
.withHelper('world', function(thing, options) { .withHelper('world', function (thing, options) {
return options.data.adjective + ' ' + thing + (this.exclaim || ''); return options.data.adjective + ' ' + thing + (this.exclaim || '');
}) })
.withInput({ exclaim: true, zomg: 'world' }) .withInput({ exclaim: true, zomg: 'world' })
@@ -203,16 +203,16 @@ describe('data', function() {
.toCompileTo('#win happy world?'); .toCompileTo('#win happy world?');
}); });
it('you can override inherited data when invoking a helper', function() { it('you can override inherited data when invoking a helper', function () {
expectTemplate('{{#hello}}{{world zomg}}{{/hello}}') expectTemplate('{{#hello}}{{world zomg}}{{/hello}}')
.withCompileOptions({ data: true }) .withCompileOptions({ data: true })
.withHelper('hello', function(options) { .withHelper('hello', function (options) {
return options.fn( return options.fn(
{ exclaim: '?', zomg: 'world' }, { exclaim: '?', zomg: 'world' },
{ data: { adjective: 'sad' } } { data: { adjective: 'sad' } }
); );
}) })
.withHelper('world', function(thing, options) { .withHelper('world', function (thing, options) {
return options.data.adjective + ' ' + thing + (this.exclaim || ''); return options.data.adjective + ' ' + thing + (this.exclaim || '');
}) })
.withInput({ exclaim: true, zomg: 'planet' }) .withInput({ exclaim: true, zomg: 'planet' })
@@ -221,13 +221,13 @@ describe('data', function() {
.toCompileTo('sad world?'); .toCompileTo('sad world?');
}); });
it('you can override inherited data when invoking a helper with depth', function() { it('you can override inherited data when invoking a helper with depth', function () {
expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}') expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}')
.withCompileOptions({ data: true }) .withCompileOptions({ data: true })
.withHelper('hello', function(options) { .withHelper('hello', function (options) {
return options.fn({ exclaim: '?' }, { data: { adjective: 'sad' } }); return options.fn({ exclaim: '?' }, { data: { adjective: 'sad' } });
}) })
.withHelper('world', function(thing, options) { .withHelper('world', function (thing, options) {
return options.data.adjective + ' ' + thing + (this.exclaim || ''); return options.data.adjective + ' ' + thing + (this.exclaim || '');
}) })
.withInput({ exclaim: true, zomg: 'world' }) .withInput({ exclaim: true, zomg: 'world' })
@@ -236,8 +236,8 @@ describe('data', function() {
.toCompileTo('sad world?'); .toCompileTo('sad world?');
}); });
describe('@root', function() { describe('@root', function () {
it('the root context can be looked up via @root', function() { it('the root context can be looked up via @root', function () {
expectTemplate('{{@root.foo}}') expectTemplate('{{@root.foo}}')
.withInput({ foo: 'hello' }) .withInput({ foo: 'hello' })
.withRuntimeOptions({ data: {} }) .withRuntimeOptions({ data: {} })
@@ -248,7 +248,7 @@ describe('data', function() {
.toCompileTo('hello'); .toCompileTo('hello');
}); });
it('passed root values take priority', function() { it('passed root values take priority', function () {
expectTemplate('{{@root.foo}}') expectTemplate('{{@root.foo}}')
.withInput({ foo: 'should not be used' }) .withInput({ foo: 'should not be used' })
.withRuntimeOptions({ data: { root: { foo: 'hello' } } }) .withRuntimeOptions({ data: { root: { foo: 'hello' } } })
@@ -256,21 +256,21 @@ describe('data', function() {
}); });
}); });
describe('nesting', function() { describe('nesting', function () {
it('the root context can be looked up via @root', function() { it('the root context can be looked up via @root', function () {
expectTemplate( expectTemplate(
'{{#helper}}{{#helper}}{{@./depth}} {{@../depth}} {{@../../depth}}{{/helper}}{{/helper}}' '{{#helper}}{{#helper}}{{@./depth}} {{@../depth}} {{@../../depth}}{{/helper}}{{/helper}}'
) )
.withInput({ foo: 'hello' }) .withInput({ foo: 'hello' })
.withHelper('helper', function(options) { .withHelper('helper', function (options) {
var frame = Handlebars.createFrame(options.data); var frame = Handlebars.createFrame(options.data);
frame.depth = options.data.depth + 1; frame.depth = options.data.depth + 1;
return options.fn(this, { data: frame }); return options.fn(this, { data: frame });
}) })
.withRuntimeOptions({ .withRuntimeOptions({
data: { data: {
depth: 0 depth: 0,
} },
}) })
.toCompileTo('2 1 0'); .toCompileTo('2 1 0');
}); });
+3 -3
View File
@@ -26,13 +26,13 @@ vm.runInThisContext(distHandlebars, filename);
global.CompilerContext = { global.CompilerContext = {
browser: true, browser: true,
compile: function(template, options) { compile: function (template, options) {
var templateSpec = handlebarsEnv.precompile(template, options); var templateSpec = handlebarsEnv.precompile(template, options);
return handlebarsEnv.template(safeEval(templateSpec)); return handlebarsEnv.template(safeEval(templateSpec));
}, },
compileWithPartial: function(template, options) { compileWithPartial: function (template, options) {
return handlebarsEnv.compile(template, options); return handlebarsEnv.compile(template, options);
} },
}; };
function safeEval(templateSpec) { function safeEval(templateSpec) {
+24 -24
View File
@@ -1,4 +1,4 @@
var global = (function() { var global = (function () {
return this; return this;
})(); })();
@@ -21,7 +21,7 @@ if (Error.captureStackTrace) {
/** /**
* @deprecated Use "expectTemplate(template)...toCompileTo(output)" instead * @deprecated Use "expectTemplate(template)...toCompileTo(output)" instead
*/ */
global.shouldCompileTo = function(string, hashOrArray, expected, message) { global.shouldCompileTo = function (string, hashOrArray, expected, message) {
shouldCompileToWithPartials(string, hashOrArray, false, expected, message); shouldCompileToWithPartials(string, hashOrArray, false, expected, message);
}; };
@@ -47,7 +47,7 @@ global.shouldCompileToWithPartials = function shouldCompileToWithPartials(
/** /**
* @deprecated Use "expectTemplate(template)...toCompileTo(output)" instead * @deprecated Use "expectTemplate(template)...toCompileTo(output)" instead
*/ */
global.compileWithPartials = function(string, hashOrArray, partials) { global.compileWithPartials = function (string, hashOrArray, partials) {
var template, ary, options; var template, ary, options;
if (hashOrArray && hashOrArray.hash) { if (hashOrArray && hashOrArray.hash) {
ary = [hashOrArray.hash, hashOrArray]; ary = [hashOrArray.hash, hashOrArray];
@@ -92,7 +92,7 @@ global.equals = global.equal = function equals(a, b, msg) {
* @deprecated Use chai's expect-style API instead (`expect(actualValue).to.equal(expectedValue)`) * @deprecated Use chai's expect-style API instead (`expect(actualValue).to.equal(expectedValue)`)
* @see https://www.chaijs.com/api/bdd/#method_throw * @see https://www.chaijs.com/api/bdd/#method_throw
*/ */
global.shouldThrow = function(callback, type, msg) { global.shouldThrow = function (callback, type, msg) {
var failed; var failed;
try { try {
callback(); callback();
@@ -121,7 +121,7 @@ global.shouldThrow = function(callback, type, msg) {
} }
}; };
global.expectTemplate = function(templateAsString) { global.expectTemplate = function (templateAsString) {
return new HandlebarsTestBench(templateAsString); return new HandlebarsTestBench(templateAsString);
}; };
@@ -137,38 +137,38 @@ function HandlebarsTestBench(templateAsString) {
this.runtimeOptions = {}; this.runtimeOptions = {};
} }
HandlebarsTestBench.prototype.withInput = function(input) { HandlebarsTestBench.prototype.withInput = function (input) {
this.input = input; this.input = input;
return this; return this;
}; };
HandlebarsTestBench.prototype.withHelper = function(name, helperFunction) { HandlebarsTestBench.prototype.withHelper = function (name, helperFunction) {
this.helpers[name] = helperFunction; this.helpers[name] = helperFunction;
return this; return this;
}; };
HandlebarsTestBench.prototype.withHelpers = function(helperFunctions) { HandlebarsTestBench.prototype.withHelpers = function (helperFunctions) {
var self = this; var self = this;
Object.keys(helperFunctions).forEach(function(name) { Object.keys(helperFunctions).forEach(function (name) {
self.withHelper(name, helperFunctions[name]); self.withHelper(name, helperFunctions[name]);
}); });
return this; return this;
}; };
HandlebarsTestBench.prototype.withPartial = function(name, partialAsString) { HandlebarsTestBench.prototype.withPartial = function (name, partialAsString) {
this.partials[name] = partialAsString; this.partials[name] = partialAsString;
return this; return this;
}; };
HandlebarsTestBench.prototype.withPartials = function(partials) { HandlebarsTestBench.prototype.withPartials = function (partials) {
var self = this; var self = this;
Object.keys(partials).forEach(function(name) { Object.keys(partials).forEach(function (name) {
self.withPartial(name, partials[name]); self.withPartial(name, partials[name]);
}); });
return this; return this;
}; };
HandlebarsTestBench.prototype.withDecorator = function( HandlebarsTestBench.prototype.withDecorator = function (
name, name,
decoratorFunction decoratorFunction
) { ) {
@@ -176,30 +176,30 @@ HandlebarsTestBench.prototype.withDecorator = function(
return this; return this;
}; };
HandlebarsTestBench.prototype.withDecorators = function(decorators) { HandlebarsTestBench.prototype.withDecorators = function (decorators) {
var self = this; var self = this;
Object.keys(decorators).forEach(function(name) { Object.keys(decorators).forEach(function (name) {
self.withDecorator(name, decorators[name]); self.withDecorator(name, decorators[name]);
}); });
return this; return this;
}; };
HandlebarsTestBench.prototype.withCompileOptions = function(compileOptions) { HandlebarsTestBench.prototype.withCompileOptions = function (compileOptions) {
this.compileOptions = compileOptions; this.compileOptions = compileOptions;
return this; return this;
}; };
HandlebarsTestBench.prototype.withRuntimeOptions = function(runtimeOptions) { HandlebarsTestBench.prototype.withRuntimeOptions = function (runtimeOptions) {
this.runtimeOptions = runtimeOptions; this.runtimeOptions = runtimeOptions;
return this; return this;
}; };
HandlebarsTestBench.prototype.withMessage = function(message) { HandlebarsTestBench.prototype.withMessage = function (message) {
this.message = message; this.message = message;
return this; return this;
}; };
HandlebarsTestBench.prototype.toCompileTo = function(expectedOutputAsString) { HandlebarsTestBench.prototype.toCompileTo = function (expectedOutputAsString) {
expect(this._compileAndExecute()).to.equal( expect(this._compileAndExecute()).to.equal(
expectedOutputAsString, expectedOutputAsString,
this.message this.message
@@ -207,14 +207,14 @@ HandlebarsTestBench.prototype.toCompileTo = function(expectedOutputAsString) {
}; };
// see chai "to.throw" (https://www.chaijs.com/api/bdd/#method_throw) // see chai "to.throw" (https://www.chaijs.com/api/bdd/#method_throw)
HandlebarsTestBench.prototype.toThrow = function(errorLike, errMsgMatcher) { HandlebarsTestBench.prototype.toThrow = function (errorLike, errMsgMatcher) {
var self = this; var self = this;
expect(function() { expect(function () {
self._compileAndExecute(); self._compileAndExecute();
}).to.throw(errorLike, errMsgMatcher, this.message); }).to.throw(errorLike, errMsgMatcher, this.message);
}; };
HandlebarsTestBench.prototype._compileAndExecute = function() { HandlebarsTestBench.prototype._compileAndExecute = function () {
var compile = var compile =
Object.keys(this.partials).length > 0 Object.keys(this.partials).length > 0
? CompilerContext.compileWithPartial ? CompilerContext.compileWithPartial
@@ -226,10 +226,10 @@ HandlebarsTestBench.prototype._compileAndExecute = function() {
return template(this.input, combinedRuntimeOptions); return template(this.input, combinedRuntimeOptions);
}; };
HandlebarsTestBench.prototype._combineRuntimeOptions = function() { HandlebarsTestBench.prototype._combineRuntimeOptions = function () {
var self = this; var self = this;
var combinedRuntimeOptions = {}; var combinedRuntimeOptions = {};
Object.keys(this.runtimeOptions).forEach(function(key) { Object.keys(this.runtimeOptions).forEach(function (key) {
combinedRuntimeOptions[key] = self.runtimeOptions[key]; combinedRuntimeOptions[key] = self.runtimeOptions[key];
}); });
combinedRuntimeOptions.helpers = this.helpers; combinedRuntimeOptions.helpers = this.helpers;
+3 -3
View File
@@ -11,13 +11,13 @@ global.sinon = require('sinon');
global.Handlebars = require('../../lib'); global.Handlebars = require('../../lib');
global.CompilerContext = { global.CompilerContext = {
compile: function(template, options) { compile: function (template, options) {
var templateSpec = handlebarsEnv.precompile(template, options); var templateSpec = handlebarsEnv.precompile(template, options);
return handlebarsEnv.template(safeEval(templateSpec)); return handlebarsEnv.template(safeEval(templateSpec));
}, },
compileWithPartial: function(template, options) { compileWithPartial: function (template, options) {
return handlebarsEnv.compile(template, options); return handlebarsEnv.compile(template, options);
} },
}; };
function safeEval(templateSpec) { function safeEval(templateSpec) {
+9 -9
View File
@@ -15,25 +15,25 @@ if (grep === '--min') {
var files = fs var files = fs
.readdirSync(testDir) .readdirSync(testDir)
.filter(function(name) { .filter(function (name) {
return /.*\.js$/.test(name); return /.*\.js$/.test(name);
}) })
.map(function(name) { .map(function (name) {
return testDir + path.sep + name; return testDir + path.sep + name;
}); });
if (global.minimizedTest) { if (global.minimizedTest) {
run('./runtime', function() { run('./runtime', function () {
run('./browser', function() { run('./browser', function () {
/* eslint-disable no-process-exit */ /* eslint-disable no-process-exit */
process.exit(errors); process.exit(errors);
/* eslint-enable no-process-exit */ /* eslint-enable no-process-exit */
}); });
}); });
} else { } else {
run('./runtime', function() { run('./runtime', function () {
run('./browser', function() { run('./browser', function () {
run('./node', function() { run('./node', function () {
/* eslint-disable no-process-exit */ /* eslint-disable no-process-exit */
process.exit(errors); process.exit(errors);
/* eslint-enable no-process-exit */ /* eslint-enable no-process-exit */
@@ -50,13 +50,13 @@ function run(env, callback) {
mocha.grep(grep); mocha.grep(grep);
} }
files.forEach(function(name) { files.forEach(function (name) {
delete require.cache[name]; delete require.cache[name];
}); });
console.log('Running env: ' + env); console.log('Running env: ' + env);
require(env); require(env);
mocha.run(function(errorCount) { mocha.run(function (errorCount) {
errors += errorCount; errors += errorCount;
callback(); callback();
}); });
+8 -5
View File
@@ -29,9 +29,12 @@ var JavaScriptCompiler = require('../../dist/cjs/handlebars/compiler/javascript-
global.CompilerContext = { global.CompilerContext = {
browser: true, browser: true,
compile: function(template, options) { compile: function (template, options) {
// Hack the compiler on to the environment for these specific tests // Hack the compiler on to the environment for these specific tests
handlebarsEnv.precompile = function(precompileTemplate, precompileOptions) { handlebarsEnv.precompile = function (
precompileTemplate,
precompileOptions
) {
return compiler.precompile( return compiler.precompile(
precompileTemplate, precompileTemplate,
precompileOptions, precompileOptions,
@@ -45,9 +48,9 @@ global.CompilerContext = {
var templateSpec = handlebarsEnv.precompile(template, options); var templateSpec = handlebarsEnv.precompile(template, options);
return handlebarsEnv.template(safeEval(templateSpec)); return handlebarsEnv.template(safeEval(templateSpec));
}, },
compileWithPartial: function(template, options) { compileWithPartial: function (template, options) {
// Hack the compiler on to the environment for these specific tests // Hack the compiler on to the environment for these specific tests
handlebarsEnv.compile = function(compileTemplate, compileOptions) { handlebarsEnv.compile = function (compileTemplate, compileOptions) {
return compiler.compile(compileTemplate, compileOptions, handlebarsEnv); return compiler.compile(compileTemplate, compileOptions, handlebarsEnv);
}; };
handlebarsEnv.parse = parse; handlebarsEnv.parse = parse;
@@ -55,7 +58,7 @@ global.CompilerContext = {
handlebarsEnv.JavaScriptCompiler = JavaScriptCompiler; handlebarsEnv.JavaScriptCompiler = JavaScriptCompiler;
return handlebarsEnv.compile(template, options); return handlebarsEnv.compile(template, options);
} },
}; };
function safeEval(templateSpec) { function safeEval(templateSpec) {
+200 -200
View File
File diff suppressed because it is too large Load Diff
+30 -28
View File
@@ -1,19 +1,19 @@
describe('javascript-compiler api', function() { describe('javascript-compiler api', function () {
if (!Handlebars.JavaScriptCompiler) { if (!Handlebars.JavaScriptCompiler) {
return; return;
} }
describe('#nameLookup', function() { describe('#nameLookup', function () {
var $superName; var $superName;
beforeEach(function() { beforeEach(function () {
$superName = handlebarsEnv.JavaScriptCompiler.prototype.nameLookup; $superName = handlebarsEnv.JavaScriptCompiler.prototype.nameLookup;
}); });
afterEach(function() { afterEach(function () {
handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = $superName; handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = $superName;
}); });
it('should allow override', function() { it('should allow override', function () {
handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = function( handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = function (
parent, parent,
name name
) { ) {
@@ -28,27 +28,27 @@ describe('javascript-compiler api', function() {
// Tests nameLookup dot vs. bracket behavior. Bracket is required in certain cases // Tests nameLookup dot vs. bracket behavior. Bracket is required in certain cases
// to avoid errors in older browsers. // to avoid errors in older browsers.
it('should handle reserved words', function() { it('should handle reserved words', function () {
expectTemplate('{{foo}} {{~null~}}') expectTemplate('{{foo}} {{~null~}}')
.withInput({ foo: 'food' }) .withInput({ foo: 'food' })
.toCompileTo('food'); .toCompileTo('food');
}); });
}); });
describe('#compilerInfo', function() { describe('#compilerInfo', function () {
var $superCheck, $superInfo; var $superCheck, $superInfo;
beforeEach(function() { beforeEach(function () {
$superCheck = handlebarsEnv.VM.checkRevision; $superCheck = handlebarsEnv.VM.checkRevision;
$superInfo = handlebarsEnv.JavaScriptCompiler.prototype.compilerInfo; $superInfo = handlebarsEnv.JavaScriptCompiler.prototype.compilerInfo;
}); });
afterEach(function() { afterEach(function () {
handlebarsEnv.VM.checkRevision = $superCheck; handlebarsEnv.VM.checkRevision = $superCheck;
handlebarsEnv.JavaScriptCompiler.prototype.compilerInfo = $superInfo; handlebarsEnv.JavaScriptCompiler.prototype.compilerInfo = $superInfo;
}); });
it('should allow compilerInfo override', function() { it('should allow compilerInfo override', function () {
handlebarsEnv.JavaScriptCompiler.prototype.compilerInfo = function() { handlebarsEnv.JavaScriptCompiler.prototype.compilerInfo = function () {
return 'crazy'; return 'crazy';
}; };
handlebarsEnv.VM.checkRevision = function(compilerInfo) { handlebarsEnv.VM.checkRevision = function (compilerInfo) {
if (compilerInfo !== 'crazy') { if (compilerInfo !== 'crazy') {
throw new Error("It didn't work"); throw new Error("It didn't work");
} }
@@ -58,30 +58,32 @@ describe('javascript-compiler api', function() {
.toCompileTo('food '); .toCompileTo('food ');
}); });
}); });
describe('buffer', function() { describe('buffer', function () {
var $superAppend, $superCreate; var $superAppend, $superCreate;
beforeEach(function() { beforeEach(function () {
handlebarsEnv.JavaScriptCompiler.prototype.forceBuffer = true; handlebarsEnv.JavaScriptCompiler.prototype.forceBuffer = true;
$superAppend = handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer; $superAppend = handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer;
$superCreate = $superCreate =
handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer; handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer;
}); });
afterEach(function() { afterEach(function () {
handlebarsEnv.JavaScriptCompiler.prototype.forceBuffer = false; handlebarsEnv.JavaScriptCompiler.prototype.forceBuffer = false;
handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = $superAppend; handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = $superAppend;
handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer = $superCreate; handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer =
$superCreate;
}); });
it('should allow init buffer override', function() { it('should allow init buffer override', function () {
handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer = function() { handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer =
return this.quotedString('foo_'); function () {
}; return this.quotedString('foo_');
};
expectTemplate('{{foo}} ') expectTemplate('{{foo}} ')
.withInput({ foo: 'food' }) .withInput({ foo: 'food' })
.toCompileTo('foo_food '); .toCompileTo('foo_food ');
}); });
it('should allow append buffer override', function() { it('should allow append buffer override', function () {
handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = function( handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = function (
string string
) { ) {
return $superAppend.call(this, [string, ' + "_foo"']); return $superAppend.call(this, [string, ' + "_foo"']);
@@ -92,13 +94,13 @@ describe('javascript-compiler api', function() {
}); });
}); });
describe('#isValidJavaScriptVariableName', function() { describe('#isValidJavaScriptVariableName', function () {
// It is there and accessible and could be used by someone. That's why we don't remove it // It is there and accessible and could be used by someone. That's why we don't remove it
// it 4.x. But if we keep it, we add a test // it 4.x. But if we keep it, we add a test
// This test should not encourage you to use the function. It is not needed any more // This test should not encourage you to use the function. It is not needed any more
// and might be removed in 5.0 // and might be removed in 5.0
['test', 'abc123', 'abc_123'].forEach(function(validVariableName) { ['test', 'abc123', 'abc_123'].forEach(function (validVariableName) {
it("should return true for '" + validVariableName + "'", function() { it("should return true for '" + validVariableName + "'", function () {
expect( expect(
handlebarsEnv.JavaScriptCompiler.isValidJavaScriptVariableName( handlebarsEnv.JavaScriptCompiler.isValidJavaScriptVariableName(
validVariableName validVariableName
@@ -106,8 +108,8 @@ describe('javascript-compiler api', function() {
).to.be.true(); ).to.be.true();
}); });
}); });
[('123test', 'abc()', 'abc.cde')].forEach(function(invalidVariableName) { [('123test', 'abc()', 'abc.cde')].forEach(function (invalidVariableName) {
it("should return true for '" + invalidVariableName + "'", function() { it("should return true for '" + invalidVariableName + "'", function () {
expect( expect(
handlebarsEnv.JavaScriptCompiler.isValidJavaScriptVariableName( handlebarsEnv.JavaScriptCompiler.isValidJavaScriptVariableName(
invalidVariableName invalidVariableName
+118 -121
View File
@@ -1,12 +1,12 @@
describe('partials', function() { describe('partials', function () {
it('basic partials', function() { it('basic partials', function () {
var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}'; var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
var partial = '{{name}} ({{url}}) '; var partial = '{{name}} ({{url}}) ';
var hash = { var hash = {
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}; };
expectTemplate(string) expectTemplate(string)
@@ -22,19 +22,19 @@ describe('partials', function() {
.toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) '); .toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
}); });
it('dynamic partials', function() { it('dynamic partials', function () {
var string = 'Dudes: {{#dudes}}{{> (partial)}}{{/dudes}}'; var string = 'Dudes: {{#dudes}}{{> (partial)}}{{/dudes}}';
var partial = '{{name}} ({{url}}) '; var partial = '{{name}} ({{url}}) ';
var hash = { var hash = {
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}; };
var helpers = { var helpers = {
partial: function() { partial: function () {
return 'dude'; return 'dude';
} },
}; };
expectTemplate(string) expectTemplate(string)
@@ -52,41 +52,41 @@ describe('partials', function() {
.toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) '); .toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
}); });
it('failing dynamic partials', function() { it('failing dynamic partials', function () {
expectTemplate('Dudes: {{#dudes}}{{> (partial)}}{{/dudes}}') expectTemplate('Dudes: {{#dudes}}{{> (partial)}}{{/dudes}}')
.withInput({ .withInput({
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withHelper('partial', function() { .withHelper('partial', function () {
return 'missing'; return 'missing';
}) })
.withPartial('dude', '{{name}} ({{url}}) ') .withPartial('dude', '{{name}} ({{url}}) ')
.toThrow(Handlebars.Exception, 'The partial missing could not be found'); .toThrow(Handlebars.Exception, 'The partial missing could not be found');
}); });
it('partials with context', function() { it('partials with context', function () {
expectTemplate('Dudes: {{>dude dudes}}') expectTemplate('Dudes: {{>dude dudes}}')
.withInput({ .withInput({
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartial('dude', '{{#this}}{{name}} ({{url}}) {{/this}}') .withPartial('dude', '{{#this}}{{name}} ({{url}}) {{/this}}')
.withMessage('Partials can be passed a context') .withMessage('Partials can be passed a context')
.toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) '); .toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
}); });
it('partials with no context', function() { it('partials with no context', function () {
var partial = '{{name}} ({{url}}) '; var partial = '{{name}} ({{url}}) ';
var hash = { var hash = {
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}; };
expectTemplate('Dudes: {{#dudes}}{{>dude}}{{/dudes}}') expectTemplate('Dudes: {{#dudes}}{{>dude}}{{/dudes}}')
@@ -102,50 +102,50 @@ describe('partials', function() {
.toCompileTo('Dudes: foo () foo () '); .toCompileTo('Dudes: foo () foo () ');
}); });
it('partials with string context', function() { it('partials with string context', function () {
expectTemplate('Dudes: {{>dude "dudes"}}') expectTemplate('Dudes: {{>dude "dudes"}}')
.withPartial('dude', '{{.}}') .withPartial('dude', '{{.}}')
.toCompileTo('Dudes: dudes'); .toCompileTo('Dudes: dudes');
}); });
it('partials with undefined context', function() { it('partials with undefined context', function () {
expectTemplate('Dudes: {{>dude dudes}}') expectTemplate('Dudes: {{>dude dudes}}')
.withPartial('dude', '{{foo}} Empty') .withPartial('dude', '{{foo}} Empty')
.toCompileTo('Dudes: Empty'); .toCompileTo('Dudes: Empty');
}); });
it('partials with duplicate parameters', function() { it('partials with duplicate parameters', function () {
expectTemplate('Dudes: {{>dude dudes foo bar=baz}}').toThrow( expectTemplate('Dudes: {{>dude dudes foo bar=baz}}').toThrow(
Error, Error,
'Unsupported number of partial arguments: 2 - 1:7' 'Unsupported number of partial arguments: 2 - 1:7'
); );
}); });
it('partials with parameters', function() { it('partials with parameters', function () {
expectTemplate('Dudes: {{#dudes}}{{> dude others=..}}{{/dudes}}') expectTemplate('Dudes: {{#dudes}}{{> dude others=..}}{{/dudes}}')
.withInput({ .withInput({
foo: 'bar', foo: 'bar',
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartial('dude', '{{others.foo}}{{name}} ({{url}}) ') .withPartial('dude', '{{others.foo}}{{name}} ({{url}}) ')
.withMessage('Basic partials output based on current context.') .withMessage('Basic partials output based on current context.')
.toCompileTo('Dudes: barYehuda (http://yehuda) barAlan (http://alan) '); .toCompileTo('Dudes: barYehuda (http://yehuda) barAlan (http://alan) ');
}); });
it('partial in a partial', function() { it('partial in a partial', function () {
expectTemplate('Dudes: {{#dudes}}{{>dude}}{{/dudes}}') expectTemplate('Dudes: {{#dudes}}{{>dude}}{{/dudes}}')
.withInput({ .withInput({
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartials({ .withPartials({
dude: '{{name}} {{> url}} ', dude: '{{name}} {{> url}} ',
url: '<a href="{{url}}">{{url}}</a>' url: '<a href="{{url}}">{{url}}</a>',
}) })
.withMessage('Partials are rendered inside of other partials') .withMessage('Partials are rendered inside of other partials')
.toCompileTo( .toCompileTo(
@@ -153,16 +153,16 @@ describe('partials', function() {
); );
}); });
it('rendering undefined partial throws an exception', function() { it('rendering undefined partial throws an exception', function () {
expectTemplate('{{> whatever}}').toThrow( expectTemplate('{{> whatever}}').toThrow(
Handlebars.Exception, Handlebars.Exception,
'The partial whatever could not be found' 'The partial whatever could not be found'
); );
}); });
it('registering undefined partial throws an exception', function() { it('registering undefined partial throws an exception', function () {
shouldThrow( shouldThrow(
function() { function () {
var undef; var undef;
handlebarsEnv.registerPartial('undefined_test', undef); handlebarsEnv.registerPartial('undefined_test', undef);
}, },
@@ -171,14 +171,14 @@ describe('partials', function() {
); );
}); });
it('rendering template partial in vm mode throws an exception', function() { it('rendering template partial in vm mode throws an exception', function () {
expectTemplate('{{> whatever}}').toThrow( expectTemplate('{{> whatever}}').toThrow(
Handlebars.Exception, Handlebars.Exception,
'The partial whatever could not be found' 'The partial whatever could not be found'
); );
}); });
it('rendering function partial in vm mode', function() { it('rendering function partial in vm mode', function () {
function partial(context) { function partial(context) {
return context.name + ' (' + context.url + ') '; return context.name + ' (' + context.url + ') ';
} }
@@ -186,15 +186,15 @@ describe('partials', function() {
.withInput({ .withInput({
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartial('dude', partial) .withPartial('dude', partial)
.withMessage('Function partials output based in VM.') .withMessage('Function partials output based in VM.')
.toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) '); .toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
}); });
it('GH-14: a partial preceding a selector', function() { it('GH-14: a partial preceding a selector', function () {
expectTemplate('Dudes: {{>dude}} {{anotherDude}}') expectTemplate('Dudes: {{>dude}} {{anotherDude}}')
.withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withInput({ name: 'Jeepers', anotherDude: 'Creepers' })
.withPartial('dude', '{{name}}') .withPartial('dude', '{{name}}')
@@ -202,7 +202,7 @@ describe('partials', function() {
.toCompileTo('Dudes: Jeepers Creepers'); .toCompileTo('Dudes: Jeepers Creepers');
}); });
it('Partials with slash paths', function() { it('Partials with slash paths', function () {
expectTemplate('Dudes: {{> shared/dude}}') expectTemplate('Dudes: {{> shared/dude}}')
.withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withInput({ name: 'Jeepers', anotherDude: 'Creepers' })
.withPartial('shared/dude', '{{name}}') .withPartial('shared/dude', '{{name}}')
@@ -210,7 +210,7 @@ describe('partials', function() {
.toCompileTo('Dudes: Jeepers'); .toCompileTo('Dudes: Jeepers');
}); });
it('Partials with slash and point paths', function() { it('Partials with slash and point paths', function () {
expectTemplate('Dudes: {{> shared/dude.thing}}') expectTemplate('Dudes: {{> shared/dude.thing}}')
.withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withInput({ name: 'Jeepers', anotherDude: 'Creepers' })
.withPartial('shared/dude.thing', '{{name}}') .withPartial('shared/dude.thing', '{{name}}')
@@ -218,7 +218,7 @@ describe('partials', function() {
.toCompileTo('Dudes: Jeepers'); .toCompileTo('Dudes: Jeepers');
}); });
it('Global Partials', function() { it('Global Partials', function () {
handlebarsEnv.registerPartial('globalTest', '{{anotherDude}}'); handlebarsEnv.registerPartial('globalTest', '{{anotherDude}}');
expectTemplate('Dudes: {{> shared/dude}} {{> globalTest}}') expectTemplate('Dudes: {{> shared/dude}} {{> globalTest}}')
@@ -231,10 +231,10 @@ describe('partials', function() {
equals(handlebarsEnv.partials.globalTest, undefined); equals(handlebarsEnv.partials.globalTest, undefined);
}); });
it('Multiple partial registration', function() { it('Multiple partial registration', function () {
handlebarsEnv.registerPartial({ handlebarsEnv.registerPartial({
'shared/dude': '{{name}}', 'shared/dude': '{{name}}',
globalTest: '{{anotherDude}}' globalTest: '{{anotherDude}}',
}); });
expectTemplate('Dudes: {{> shared/dude}} {{> globalTest}}') expectTemplate('Dudes: {{> shared/dude}} {{> globalTest}}')
@@ -244,7 +244,7 @@ describe('partials', function() {
.toCompileTo('Dudes: Jeepers Creepers'); .toCompileTo('Dudes: Jeepers Creepers');
}); });
it('Partials with integer path', function() { it('Partials with integer path', function () {
expectTemplate('Dudes: {{> 404}}') expectTemplate('Dudes: {{> 404}}')
.withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withInput({ name: 'Jeepers', anotherDude: 'Creepers' })
.withPartial(404, '{{name}}') .withPartial(404, '{{name}}')
@@ -252,7 +252,7 @@ describe('partials', function() {
.toCompileTo('Dudes: Jeepers'); .toCompileTo('Dudes: Jeepers');
}); });
it('Partials with complex path', function() { it('Partials with complex path', function () {
expectTemplate('Dudes: {{> 404/asdf?.bar}}') expectTemplate('Dudes: {{> 404/asdf?.bar}}')
.withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withInput({ name: 'Jeepers', anotherDude: 'Creepers' })
.withPartial('404/asdf?.bar', '{{name}}') .withPartial('404/asdf?.bar', '{{name}}')
@@ -260,7 +260,7 @@ describe('partials', function() {
.toCompileTo('Dudes: Jeepers'); .toCompileTo('Dudes: Jeepers');
}); });
it('Partials with escaped', function() { it('Partials with escaped', function () {
expectTemplate('Dudes: {{> [+404/asdf?.bar]}}') expectTemplate('Dudes: {{> [+404/asdf?.bar]}}')
.withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withInput({ name: 'Jeepers', anotherDude: 'Creepers' })
.withPartial('+404/asdf?.bar', '{{name}}') .withPartial('+404/asdf?.bar', '{{name}}')
@@ -268,7 +268,7 @@ describe('partials', function() {
.toCompileTo('Dudes: Jeepers'); .toCompileTo('Dudes: Jeepers');
}); });
it('Partials with string', function() { it('Partials with string', function () {
expectTemplate("Dudes: {{> '+404/asdf?.bar'}}") expectTemplate("Dudes: {{> '+404/asdf?.bar'}}")
.withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withInput({ name: 'Jeepers', anotherDude: 'Creepers' })
.withPartial('+404/asdf?.bar', '{{name}}') .withPartial('+404/asdf?.bar', '{{name}}')
@@ -276,19 +276,19 @@ describe('partials', function() {
.toCompileTo('Dudes: Jeepers'); .toCompileTo('Dudes: Jeepers');
}); });
it('should handle empty partial', function() { it('should handle empty partial', function () {
expectTemplate('Dudes: {{#dudes}}{{> dude}}{{/dudes}}') expectTemplate('Dudes: {{#dudes}}{{> dude}}{{/dudes}}')
.withInput({ .withInput({
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartial('dude', '') .withPartial('dude', '')
.toCompileTo('Dudes: '); .toCompileTo('Dudes: ');
}); });
it('throw on missing partial', function() { it('throw on missing partial', function () {
var compile = handlebarsEnv.compile; var compile = handlebarsEnv.compile;
var compileWithPartial = CompilerContext.compileWithPartial; var compileWithPartial = CompilerContext.compileWithPartial;
handlebarsEnv.compile = undefined; handlebarsEnv.compile = undefined;
@@ -300,18 +300,18 @@ describe('partials', function() {
CompilerContext.compileWithPartial = compileWithPartial; CompilerContext.compileWithPartial = compileWithPartial;
}); });
describe('partial blocks', function() { describe('partial blocks', function () {
it('should render partial block as default', function() { it('should render partial block as default', function () {
expectTemplate('{{#> dude}}success{{/dude}}').toCompileTo('success'); expectTemplate('{{#> dude}}success{{/dude}}').toCompileTo('success');
}); });
it('should execute default block with proper context', function() { it('should execute default block with proper context', function () {
expectTemplate('{{#> dude context}}{{value}}{{/dude}}') expectTemplate('{{#> dude context}}{{value}}{{/dude}}')
.withInput({ context: { value: 'success' } }) .withInput({ context: { value: 'success' } })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should propagate block parameters to default block', function() { it('should propagate block parameters to default block', function () {
expectTemplate( expectTemplate(
'{{#with context as |me|}}{{#> dude}}{{me.value}}{{/dude}}{{/with}}' '{{#with context as |me|}}{{#> dude}}{{me.value}}{{/dude}}{{/with}}'
) )
@@ -319,79 +319,76 @@ describe('partials', function() {
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should not use partial block if partial exists', function() { it('should not use partial block if partial exists', function () {
expectTemplate('{{#> dude}}fail{{/dude}}') expectTemplate('{{#> dude}}fail{{/dude}}')
.withPartials({ dude: 'success' }) .withPartials({ dude: 'success' })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should render block from partial', function() { it('should render block from partial', function () {
expectTemplate('{{#> dude}}success{{/dude}}') expectTemplate('{{#> dude}}success{{/dude}}')
.withPartials({ dude: '{{> @partial-block }}' }) .withPartials({ dude: '{{> @partial-block }}' })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should be able to render the partial-block twice', function() { it('should be able to render the partial-block twice', function () {
expectTemplate('{{#> dude}}success{{/dude}}') expectTemplate('{{#> dude}}success{{/dude}}')
.withPartials({ dude: '{{> @partial-block }} {{> @partial-block }}' }) .withPartials({ dude: '{{> @partial-block }} {{> @partial-block }}' })
.toCompileTo('success success'); .toCompileTo('success success');
}); });
it('should render block from partial with context', function() { it('should render block from partial with context', function () {
expectTemplate('{{#> dude}}{{value}}{{/dude}}') expectTemplate('{{#> dude}}{{value}}{{/dude}}')
.withInput({ context: { value: 'success' } }) .withInput({ context: { value: 'success' } })
.withPartials({ .withPartials({
dude: '{{#with context}}{{> @partial-block }}{{/with}}' dude: '{{#with context}}{{> @partial-block }}{{/with}}',
}) })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should be able to access the @data frame from a partial-block', function() { it('should be able to access the @data frame from a partial-block', function () {
expectTemplate('{{#> dude}}in-block: {{@root/value}}{{/dude}}') expectTemplate('{{#> dude}}in-block: {{@root/value}}{{/dude}}')
.withInput({ value: 'success' }) .withInput({ value: 'success' })
.withPartials({ .withPartials({
dude: dude: '<code>before-block: {{@root/value}} {{> @partial-block }}</code>',
'<code>before-block: {{@root/value}} {{> @partial-block }}</code>'
}) })
.toCompileTo('<code>before-block: success in-block: success</code>'); .toCompileTo('<code>before-block: success in-block: success</code>');
}); });
it('should allow the #each-helper to be used along with partial-blocks', function() { it('should allow the #each-helper to be used along with partial-blocks', function () {
expectTemplate( expectTemplate(
'<template>{{#> list value}}value = {{.}}{{/list}}</template>' '<template>{{#> list value}}value = {{.}}{{/list}}</template>'
) )
.withInput({ .withInput({
value: ['a', 'b', 'c'] value: ['a', 'b', 'c'],
}) })
.withPartials({ .withPartials({
list: list: '<list>{{#each .}}<item>{{> @partial-block}}</item>{{/each}}</list>',
'<list>{{#each .}}<item>{{> @partial-block}}</item>{{/each}}</list>'
}) })
.toCompileTo( .toCompileTo(
'<template><list><item>value = a</item><item>value = b</item><item>value = c</item></list></template>' '<template><list><item>value = a</item><item>value = b</item><item>value = c</item></list></template>'
); );
}); });
it('should render block from partial with context (twice)', function() { it('should render block from partial with context (twice)', function () {
expectTemplate('{{#> dude}}{{value}}{{/dude}}') expectTemplate('{{#> dude}}{{value}}{{/dude}}')
.withInput({ context: { value: 'success' } }) .withInput({ context: { value: 'success' } })
.withPartials({ .withPartials({
dude: dude: '{{#with context}}{{> @partial-block }} {{> @partial-block }}{{/with}}',
'{{#with context}}{{> @partial-block }} {{> @partial-block }}{{/with}}'
}) })
.toCompileTo('success success'); .toCompileTo('success success');
}); });
it('should render block from partial with context', function() { it('should render block from partial with context', function () {
expectTemplate('{{#> dude}}{{../context/value}}{{/dude}}') expectTemplate('{{#> dude}}{{../context/value}}{{/dude}}')
.withInput({ context: { value: 'success' } }) .withInput({ context: { value: 'success' } })
.withPartials({ .withPartials({
dude: '{{#with context}}{{> @partial-block }}{{/with}}' dude: '{{#with context}}{{> @partial-block }}{{/with}}',
}) })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should render block from partial with block params', function() { it('should render block from partial with block params', function () {
expectTemplate( expectTemplate(
'{{#with context as |me|}}{{#> dude}}{{me.value}}{{/dude}}{{/with}}' '{{#with context as |me|}}{{#> dude}}{{me.value}}{{/dude}}{{/with}}'
) )
@@ -400,52 +397,52 @@ describe('partials', function() {
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should render nested partial blocks', function() { it('should render nested partial blocks', function () {
expectTemplate('<template>{{#> outer}}{{value}}{{/outer}}</template>') expectTemplate('<template>{{#> outer}}{{value}}{{/outer}}</template>')
.withInput({ value: 'success' }) .withInput({ value: 'success' })
.withPartials({ .withPartials({
outer: outer:
'<outer>{{#> nested}}<outer-block>{{> @partial-block}}</outer-block>{{/nested}}</outer>', '<outer>{{#> nested}}<outer-block>{{> @partial-block}}</outer-block>{{/nested}}</outer>',
nested: '<nested>{{> @partial-block}}</nested>' nested: '<nested>{{> @partial-block}}</nested>',
}) })
.toCompileTo( .toCompileTo(
'<template><outer><nested><outer-block>success</outer-block></nested></outer></template>' '<template><outer><nested><outer-block>success</outer-block></nested></outer></template>'
); );
}); });
it('should render nested partial blocks at different nesting levels', function() { it('should render nested partial blocks at different nesting levels', function () {
expectTemplate('<template>{{#> outer}}{{value}}{{/outer}}</template>') expectTemplate('<template>{{#> outer}}{{value}}{{/outer}}</template>')
.withInput({ value: 'success' }) .withInput({ value: 'success' })
.withPartials({ .withPartials({
outer: outer:
'<outer>{{#> nested}}<outer-block>{{> @partial-block}}</outer-block>{{/nested}}{{> @partial-block}}</outer>', '<outer>{{#> nested}}<outer-block>{{> @partial-block}}</outer-block>{{/nested}}{{> @partial-block}}</outer>',
nested: '<nested>{{> @partial-block}}</nested>' nested: '<nested>{{> @partial-block}}</nested>',
}) })
.toCompileTo( .toCompileTo(
'<template><outer><nested><outer-block>success</outer-block></nested>success</outer></template>' '<template><outer><nested><outer-block>success</outer-block></nested>success</outer></template>'
); );
}); });
it('should render nested partial blocks at different nesting levels (twice)', function() { it('should render nested partial blocks at different nesting levels (twice)', function () {
expectTemplate('<template>{{#> outer}}{{value}}{{/outer}}</template>') expectTemplate('<template>{{#> outer}}{{value}}{{/outer}}</template>')
.withInput({ value: 'success' }) .withInput({ value: 'success' })
.withPartials({ .withPartials({
outer: outer:
'<outer>{{#> nested}}<outer-block>{{> @partial-block}} {{> @partial-block}}</outer-block>{{/nested}}{{> @partial-block}}+{{> @partial-block}}</outer>', '<outer>{{#> nested}}<outer-block>{{> @partial-block}} {{> @partial-block}}</outer-block>{{/nested}}{{> @partial-block}}+{{> @partial-block}}</outer>',
nested: '<nested>{{> @partial-block}}</nested>' nested: '<nested>{{> @partial-block}}</nested>',
}) })
.toCompileTo( .toCompileTo(
'<template><outer><nested><outer-block>success success</outer-block></nested>success+success</outer></template>' '<template><outer><nested><outer-block>success success</outer-block></nested>success+success</outer></template>'
); );
}); });
it('should render nested partial blocks (twice at each level)', function() { it('should render nested partial blocks (twice at each level)', function () {
expectTemplate('<template>{{#> outer}}{{value}}{{/outer}}</template>') expectTemplate('<template>{{#> outer}}{{value}}{{/outer}}</template>')
.withInput({ value: 'success' }) .withInput({ value: 'success' })
.withPartials({ .withPartials({
outer: outer:
'<outer>{{#> nested}}<outer-block>{{> @partial-block}} {{> @partial-block}}</outer-block>{{/nested}}</outer>', '<outer>{{#> nested}}<outer-block>{{> @partial-block}} {{> @partial-block}}</outer-block>{{/nested}}</outer>',
nested: '<nested>{{> @partial-block}}{{> @partial-block}}</nested>' nested: '<nested>{{> @partial-block}}{{> @partial-block}}</nested>',
}) })
.toCompileTo( .toCompileTo(
'<template><outer>' + '<template><outer>' +
@@ -455,20 +452,20 @@ describe('partials', function() {
}); });
}); });
describe('inline partials', function() { describe('inline partials', function () {
it('should define inline partials for template', function() { it('should define inline partials for template', function () {
expectTemplate( expectTemplate(
'{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}' '{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}'
).toCompileTo('success'); ).toCompileTo('success');
}); });
it('should overwrite multiple partials in the same template', function() { it('should overwrite multiple partials in the same template', function () {
expectTemplate( expectTemplate(
'{{#*inline "myPartial"}}fail{{/inline}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}' '{{#*inline "myPartial"}}fail{{/inline}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}'
).toCompileTo('success'); ).toCompileTo('success');
}); });
it('should define inline partials for block', function() { it('should define inline partials for block', function () {
expectTemplate( expectTemplate(
'{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}{{/with}}' '{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}{{/with}}'
).toCompileTo('success'); ).toCompileTo('success');
@@ -478,37 +475,37 @@ describe('partials', function() {
).toThrow(Error, /myPartial could not/); ).toThrow(Error, /myPartial could not/);
}); });
it('should override global partials', function() { it('should override global partials', function () {
expectTemplate( expectTemplate(
'{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}' '{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}'
) )
.withPartials({ .withPartials({
myPartial: function() { myPartial: function () {
return 'fail'; return 'fail';
} },
}) })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should override template partials', function() { it('should override template partials', function () {
expectTemplate( expectTemplate(
'{{#*inline "myPartial"}}fail{{/inline}}{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}{{/with}}' '{{#*inline "myPartial"}}fail{{/inline}}{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}{{/with}}'
).toCompileTo('success'); ).toCompileTo('success');
}); });
it('should override partials down the entire stack', function() { it('should override partials down the entire stack', function () {
expectTemplate( expectTemplate(
'{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{#with .}}{{#with .}}{{> myPartial}}{{/with}}{{/with}}{{/with}}' '{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{#with .}}{{#with .}}{{> myPartial}}{{/with}}{{/with}}{{/with}}'
).toCompileTo('success'); ).toCompileTo('success');
}); });
it('should define inline partials for partial call', function() { it('should define inline partials for partial call', function () {
expectTemplate('{{#*inline "myPartial"}}success{{/inline}}{{> dude}}') expectTemplate('{{#*inline "myPartial"}}success{{/inline}}{{> dude}}')
.withPartials({ dude: '{{> myPartial }}' }) .withPartials({ dude: '{{> myPartial }}' })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should define inline partials in partial block call', function() { it('should define inline partials in partial block call', function () {
expectTemplate( expectTemplate(
'{{#> dude}}{{#*inline "myPartial"}}success{{/inline}}{{/dude}}' '{{#> dude}}{{#*inline "myPartial"}}success{{/inline}}{{/dude}}'
) )
@@ -516,7 +513,7 @@ describe('partials', function() {
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should render nested inline partials', function() { it('should render nested inline partials', function () {
expectTemplate( expectTemplate(
'{{#*inline "outer"}}{{#>inner}}<outer-block>{{>@partial-block}}</outer-block>{{/inner}}{{/inline}}' + '{{#*inline "outer"}}{{#>inner}}<outer-block>{{>@partial-block}}</outer-block>{{/inner}}{{/inline}}' +
'{{#*inline "inner"}}<inner>{{>@partial-block}}</inner>{{/inline}}' + '{{#*inline "inner"}}<inner>{{>@partial-block}}</inner>{{/inline}}' +
@@ -526,7 +523,7 @@ describe('partials', function() {
.toCompileTo('<inner><outer-block>success</outer-block></inner>'); .toCompileTo('<inner><outer-block>success</outer-block></inner>');
}); });
it('should render nested inline partials with partial-blocks on different nesting levels', function() { it('should render nested inline partials with partial-blocks on different nesting levels', function () {
expectTemplate( expectTemplate(
'{{#*inline "outer"}}{{#>inner}}<outer-block>{{>@partial-block}}</outer-block>{{/inner}}{{>@partial-block}}{{/inline}}' + '{{#*inline "outer"}}{{#>inner}}<outer-block>{{>@partial-block}}</outer-block>{{/inner}}{{>@partial-block}}{{/inline}}' +
'{{#*inline "inner"}}<inner>{{>@partial-block}}</inner>{{/inline}}' + '{{#*inline "inner"}}<inner>{{>@partial-block}}</inner>{{/inline}}' +
@@ -538,7 +535,7 @@ describe('partials', function() {
); );
}); });
it('should render nested inline partials (twice at each level)', function() { it('should render nested inline partials (twice at each level)', function () {
expectTemplate( expectTemplate(
'{{#*inline "outer"}}{{#>inner}}<outer-block>{{>@partial-block}} {{>@partial-block}}</outer-block>{{/inner}}{{/inline}}' + '{{#*inline "outer"}}{{#>inner}}<outer-block>{{>@partial-block}} {{>@partial-block}}</outer-block>{{/inner}}{{/inline}}' +
'{{#*inline "inner"}}<inner>{{>@partial-block}}{{>@partial-block}}</inner>{{/inline}}' + '{{#*inline "inner"}}<inner>{{>@partial-block}}{{>@partial-block}}</inner>{{/inline}}' +
@@ -551,7 +548,7 @@ describe('partials', function() {
}); });
}); });
it('should pass compiler flags', function() { it('should pass compiler flags', function () {
if (Handlebars.compile) { if (Handlebars.compile) {
var env = Handlebars.create(); var env = Handlebars.create();
env.registerPartial('partial', '{{foo}}'); env.registerPartial('partial', '{{foo}}');
@@ -560,47 +557,47 @@ describe('partials', function() {
} }
}); });
describe('standalone partials', function() { describe('standalone partials', function () {
it('indented partials', function() { it('indented partials', function () {
expectTemplate('Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}') expectTemplate('Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}')
.withInput({ .withInput({
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartial('dude', '{{name}}\n') .withPartial('dude', '{{name}}\n')
.toCompileTo('Dudes:\n Yehuda\n Alan\n'); .toCompileTo('Dudes:\n Yehuda\n Alan\n');
}); });
it('nested indented partials', function() { it('nested indented partials', function () {
expectTemplate('Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}') expectTemplate('Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}')
.withInput({ .withInput({
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartials({ .withPartials({
dude: '{{name}}\n {{> url}}', dude: '{{name}}\n {{> url}}',
url: '{{url}}!\n' url: '{{url}}!\n',
}) })
.toCompileTo( .toCompileTo(
'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() { it('prevent nested indented partials', function () {
expectTemplate('Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}') expectTemplate('Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}')
.withInput({ .withInput({
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartials({ .withPartials({
dude: '{{name}}\n {{> url}}', dude: '{{name}}\n {{> url}}',
url: '{{url}}!\n' url: '{{url}}!\n',
}) })
.withCompileOptions({ preventIndent: true }) .withCompileOptions({ preventIndent: true })
.toCompileTo( .toCompileTo(
@@ -609,15 +606,15 @@ describe('partials', function() {
}); });
}); });
describe('compat mode', function() { describe('compat mode', function () {
it('partials can access parents', function() { it('partials can access parents', function () {
expectTemplate('Dudes: {{#dudes}}{{> dude}}{{/dudes}}') expectTemplate('Dudes: {{#dudes}}{{> dude}}{{/dudes}}')
.withInput({ .withInput({
root: 'yes', root: 'yes',
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartials({ dude: '{{name}} ({{url}}) {{root}} ' }) .withPartials({ dude: '{{name}} ({{url}}) {{root}} ' })
.withCompileOptions({ compat: true }) .withCompileOptions({ compat: true })
@@ -626,14 +623,14 @@ describe('partials', function() {
); );
}); });
it('partials can access parents with custom context', function() { it('partials can access parents with custom context', function () {
expectTemplate('Dudes: {{#dudes}}{{> dude "test"}}{{/dudes}}') expectTemplate('Dudes: {{#dudes}}{{> dude "test"}}{{/dudes}}')
.withInput({ .withInput({
root: 'yes', root: 'yes',
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartials({ dude: '{{name}} ({{url}}) {{root}} ' }) .withPartials({ dude: '{{name}} ({{url}}) {{root}} ' })
.withCompileOptions({ compat: true }) .withCompileOptions({ compat: true })
@@ -642,14 +639,14 @@ describe('partials', function() {
); );
}); });
it('partials can access parents without data', function() { it('partials can access parents without data', function () {
expectTemplate('Dudes: {{#dudes}}{{> dude}}{{/dudes}}') expectTemplate('Dudes: {{#dudes}}{{> dude}}{{/dudes}}')
.withInput({ .withInput({
root: 'yes', root: 'yes',
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartials({ dude: '{{name}} ({{url}}) {{root}} ' }) .withPartials({ dude: '{{name}} ({{url}}) {{root}} ' })
.withRuntimeOptions({ data: false }) .withRuntimeOptions({ data: false })
@@ -659,17 +656,17 @@ describe('partials', function() {
); );
}); });
it('partials inherit compat', function() { it('partials inherit compat', function () {
expectTemplate('Dudes: {{> dude}}') expectTemplate('Dudes: {{> dude}}')
.withInput({ .withInput({
root: 'yes', root: 'yes',
dudes: [ dudes: [
{ name: 'Yehuda', url: 'http://yehuda' }, { name: 'Yehuda', url: 'http://yehuda' },
{ name: 'Alan', url: 'http://alan' } { name: 'Alan', url: 'http://alan' },
] ],
}) })
.withPartials({ .withPartials({
dude: '{{#dudes}}{{name}} ({{url}}) {{root}} {{/dudes}}' dude: '{{#dudes}}{{name}} ({{url}}) {{root}} {{/dudes}}',
}) })
.withCompileOptions({ compat: true }) .withCompileOptions({ compat: true })
.toCompileTo( .toCompileTo(
+83 -83
View File
@@ -1,5 +1,5 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
describe('precompiler', function() { describe('precompiler', function () {
// NOP Under non-node environments // NOP Under non-node environments
if (typeof process === 'undefined') { if (typeof process === 'undefined') {
return; return;
@@ -19,7 +19,7 @@ describe('precompiler', function() {
emptyTemplate = { emptyTemplate = {
path: __dirname + '/artifacts/empty.handlebars', path: __dirname + '/artifacts/empty.handlebars',
name: 'empty', name: 'empty',
source: '' source: '',
}, },
file, file,
content, content,
@@ -38,7 +38,7 @@ describe('precompiler', function() {
var _resolveFilename = Module._resolveFilename; var _resolveFilename = Module._resolveFilename;
delete require.cache[require.resolve('uglify-js')]; delete require.cache[require.resolve('uglify-js')];
delete require.cache[require.resolve('../dist/cjs/precompiler')]; delete require.cache[require.resolve('../dist/cjs/precompiler')];
Module._resolveFilename = function(request, mod) { Module._resolveFilename = function (request, mod) {
if (request === 'uglify-js') { if (request === 'uglify-js') {
throw loadError; throw loadError;
} }
@@ -53,7 +53,7 @@ describe('precompiler', function() {
} }
} }
beforeEach(function() { beforeEach(function () {
precompile = Handlebars.precompile; precompile = Handlebars.precompile;
minify = uglify.minify; minify = uglify.minify;
writeFileSync = fs.writeFileSync; writeFileSync = fs.writeFileSync;
@@ -61,21 +61,21 @@ describe('precompiler', function() {
// Mock stdout and stderr // Mock stdout and stderr
logFunction = console.log; logFunction = console.log;
log = ''; log = '';
console.log = function() { console.log = function () {
log += Array.prototype.join.call(arguments, ''); log += Array.prototype.join.call(arguments, '');
}; };
errorLogFunction = console.error; errorLogFunction = console.error;
errorLog = ''; errorLog = '';
console.error = function() { console.error = function () {
errorLog += Array.prototype.join.call(arguments, ''); errorLog += Array.prototype.join.call(arguments, '');
}; };
fs.writeFileSync = function(_file, _content) { fs.writeFileSync = function (_file, _content) {
file = _file; file = _file;
content = _content; content = _content;
}; };
}); });
afterEach(function() { afterEach(function () {
Handlebars.precompile = precompile; Handlebars.precompile = precompile;
uglify.minify = minify; uglify.minify = minify;
fs.writeFileSync = writeFileSync; fs.writeFileSync = writeFileSync;
@@ -83,59 +83,59 @@ describe('precompiler', function() {
console.error = errorLogFunction; console.error = errorLogFunction;
}); });
it('should output version', function() { it('should output version', function () {
Precompiler.cli({ templates: [], version: true }); Precompiler.cli({ templates: [], version: true });
equals(log, Handlebars.VERSION); equals(log, Handlebars.VERSION);
}); });
it('should throw if lacking templates', function() { it('should throw if lacking templates', function () {
shouldThrow( shouldThrow(
function() { function () {
Precompiler.cli({ templates: [] }); Precompiler.cli({ templates: [] });
}, },
Handlebars.Exception, Handlebars.Exception,
'Must define at least one template or directory.' 'Must define at least one template or directory.'
); );
}); });
it('should handle empty/filtered directories', function() { it('should handle empty/filtered directories', function () {
Precompiler.cli({ hasDirectory: true, templates: [] }); Precompiler.cli({ hasDirectory: true, templates: [] });
// Success is not throwing // Success is not throwing
}); });
it('should throw when combining simple and minimized', function() { it('should throw when combining simple and minimized', function () {
shouldThrow( shouldThrow(
function() { function () {
Precompiler.cli({ templates: [__dirname], simple: true, min: true }); Precompiler.cli({ templates: [__dirname], simple: true, min: true });
}, },
Handlebars.Exception, Handlebars.Exception,
'Unable to minimize simple output' 'Unable to minimize simple output'
); );
}); });
it('should throw when combining simple and multiple templates', function() { it('should throw when combining simple and multiple templates', function () {
shouldThrow( shouldThrow(
function() { function () {
Precompiler.cli({ Precompiler.cli({
templates: [ templates: [
__dirname + '/artifacts/empty.handlebars', __dirname + '/artifacts/empty.handlebars',
__dirname + '/artifacts/empty.handlebars' __dirname + '/artifacts/empty.handlebars',
], ],
simple: true simple: true,
}); });
}, },
Handlebars.Exception, Handlebars.Exception,
'Unable to output multiple templates in simple mode' 'Unable to output multiple templates in simple mode'
); );
}); });
it('should throw when missing name', function() { it('should throw when missing name', function () {
shouldThrow( shouldThrow(
function() { function () {
Precompiler.cli({ templates: [{ source: '' }], amd: true }); Precompiler.cli({ templates: [{ source: '' }], amd: true });
}, },
Handlebars.Exception, Handlebars.Exception,
'Name missing for template' 'Name missing for template'
); );
}); });
it('should throw when combining simple and directories', function() { it('should throw when combining simple and directories', function () {
shouldThrow( shouldThrow(
function() { function () {
Precompiler.cli({ hasDirectory: true, templates: [1], simple: true }); Precompiler.cli({ hasDirectory: true, templates: [1], simple: true });
}, },
Handlebars.Exception, Handlebars.Exception,
@@ -143,70 +143,70 @@ describe('precompiler', function() {
); );
}); });
it('should output simple templates', function() { it('should output simple templates', function () {
Handlebars.precompile = function() { Handlebars.precompile = function () {
return 'simple'; return 'simple';
}; };
Precompiler.cli({ templates: [emptyTemplate], simple: true }); Precompiler.cli({ templates: [emptyTemplate], simple: true });
equal(log, 'simple\n'); equal(log, 'simple\n');
}); });
it('should default to simple templates', function() { it('should default to simple templates', function () {
Handlebars.precompile = function() { Handlebars.precompile = function () {
return 'simple'; return 'simple';
}; };
Precompiler.cli({ templates: [{ source: '' }] }); Precompiler.cli({ templates: [{ source: '' }] });
equal(log, 'simple\n'); equal(log, 'simple\n');
}); });
it('should output amd templates', function() { it('should output amd templates', function () {
Handlebars.precompile = function() { Handlebars.precompile = function () {
return 'amd'; return 'amd';
}; };
Precompiler.cli({ templates: [emptyTemplate], amd: true }); Precompiler.cli({ templates: [emptyTemplate], amd: true });
equal(/template\(amd\)/.test(log), true); equal(/template\(amd\)/.test(log), true);
}); });
it('should output multiple amd', function() { it('should output multiple amd', function () {
Handlebars.precompile = function() { Handlebars.precompile = function () {
return 'amd'; return 'amd';
}; };
Precompiler.cli({ Precompiler.cli({
templates: [emptyTemplate, emptyTemplate], templates: [emptyTemplate, emptyTemplate],
amd: true, amd: true,
namespace: 'foo' namespace: 'foo',
}); });
equal(/templates = foo = foo \|\|/.test(log), true); equal(/templates = foo = foo \|\|/.test(log), true);
equal(/return templates/.test(log), true); equal(/return templates/.test(log), true);
equal(/template\(amd\)/.test(log), true); equal(/template\(amd\)/.test(log), true);
}); });
it('should output amd partials', function() { it('should output amd partials', function () {
Handlebars.precompile = function() { Handlebars.precompile = function () {
return 'amd'; return 'amd';
}; };
Precompiler.cli({ templates: [emptyTemplate], amd: true, partial: true }); Precompiler.cli({ templates: [emptyTemplate], amd: true, partial: true });
equal(/return Handlebars\.partials\['empty'\]/.test(log), true); equal(/return Handlebars\.partials\['empty'\]/.test(log), true);
equal(/template\(amd\)/.test(log), true); equal(/template\(amd\)/.test(log), true);
}); });
it('should output multiple amd partials', function() { it('should output multiple amd partials', function () {
Handlebars.precompile = function() { Handlebars.precompile = function () {
return 'amd'; return 'amd';
}; };
Precompiler.cli({ Precompiler.cli({
templates: [emptyTemplate, emptyTemplate], templates: [emptyTemplate, emptyTemplate],
amd: true, amd: true,
partial: true partial: true,
}); });
equal(/return Handlebars\.partials\[/.test(log), false); equal(/return Handlebars\.partials\[/.test(log), false);
equal(/template\(amd\)/.test(log), true); equal(/template\(amd\)/.test(log), true);
}); });
it('should output commonjs templates', function() { it('should output commonjs templates', function () {
Handlebars.precompile = function() { Handlebars.precompile = function () {
return 'commonjs'; return 'commonjs';
}; };
Precompiler.cli({ templates: [emptyTemplate], commonjs: true }); Precompiler.cli({ templates: [emptyTemplate], commonjs: true });
equal(/template\(commonjs\)/.test(log), true); equal(/template\(commonjs\)/.test(log), true);
}); });
it('should set data flag', function() { it('should set data flag', function () {
Handlebars.precompile = function(data, options) { Handlebars.precompile = function (data, options) {
equal(options.data, true); equal(options.data, true);
return 'simple'; return 'simple';
}; };
@@ -214,45 +214,45 @@ describe('precompiler', function() {
equal(log, 'simple\n'); equal(log, 'simple\n');
}); });
it('should set known helpers', function() { it('should set known helpers', function () {
Handlebars.precompile = function(data, options) { Handlebars.precompile = function (data, options) {
equal(options.knownHelpers.foo, true); equal(options.knownHelpers.foo, true);
return 'simple'; return 'simple';
}; };
Precompiler.cli({ templates: [emptyTemplate], simple: true, known: 'foo' }); Precompiler.cli({ templates: [emptyTemplate], simple: true, known: 'foo' });
equal(log, 'simple\n'); equal(log, 'simple\n');
}); });
it('should output to file system', function() { it('should output to file system', function () {
Handlebars.precompile = function() { Handlebars.precompile = function () {
return 'simple'; return 'simple';
}; };
Precompiler.cli({ Precompiler.cli({
templates: [emptyTemplate], templates: [emptyTemplate],
simple: true, simple: true,
output: 'file!' output: 'file!',
}); });
equal(file, 'file!'); equal(file, 'file!');
equal(content, 'simple\n'); equal(content, 'simple\n');
equal(log, ''); equal(log, '');
}); });
it('should output minimized templates', function() { it('should output minimized templates', function () {
Handlebars.precompile = function() { Handlebars.precompile = function () {
return 'amd'; return 'amd';
}; };
uglify.minify = function() { uglify.minify = function () {
return { code: 'min' }; return { code: 'min' };
}; };
Precompiler.cli({ templates: [emptyTemplate], min: true }); Precompiler.cli({ templates: [emptyTemplate], min: true });
equal(log, 'min'); equal(log, 'min');
}); });
it('should omit minimization gracefully, if uglify-js is missing', function() { it('should omit minimization gracefully, if uglify-js is missing', function () {
var error = new Error("Cannot find module 'uglify-js'"); var error = new Error("Cannot find module 'uglify-js'");
error.code = 'MODULE_NOT_FOUND'; error.code = 'MODULE_NOT_FOUND';
mockRequireUglify(error, function() { mockRequireUglify(error, function () {
var Precompiler = require('../dist/cjs/precompiler'); var Precompiler = require('../dist/cjs/precompiler');
Handlebars.precompile = function() { Handlebars.precompile = function () {
return 'amd'; return 'amd';
}; };
Precompiler.cli({ templates: [emptyTemplate], min: true }); Precompiler.cli({ templates: [emptyTemplate], min: true });
@@ -262,12 +262,12 @@ describe('precompiler', function() {
}); });
}); });
it('should fail on errors (other than missing module) while loading uglify-js', function() { it('should fail on errors (other than missing module) while loading uglify-js', function () {
mockRequireUglify(new Error('Mock Error'), function() { mockRequireUglify(new Error('Mock Error'), function () {
shouldThrow( shouldThrow(
function() { function () {
var Precompiler = require('../dist/cjs/precompiler'); var Precompiler = require('../dist/cjs/precompiler');
Handlebars.precompile = function() { Handlebars.precompile = function () {
return 'amd'; return 'amd';
}; };
Precompiler.cli({ templates: [emptyTemplate], min: true }); Precompiler.cli({ templates: [emptyTemplate], min: true });
@@ -278,35 +278,35 @@ describe('precompiler', function() {
}); });
}); });
it('should output map', function() { it('should output map', function () {
Precompiler.cli({ templates: [emptyTemplate], map: 'foo.js.map' }); Precompiler.cli({ templates: [emptyTemplate], map: 'foo.js.map' });
equal(file, 'foo.js.map'); equal(file, 'foo.js.map');
equal(log.match(/sourceMappingURL=/g).length, 1); equal(log.match(/sourceMappingURL=/g).length, 1);
}); });
it('should output map', function() { it('should output map', function () {
Precompiler.cli({ Precompiler.cli({
templates: [emptyTemplate], templates: [emptyTemplate],
min: true, min: true,
map: 'foo.js.map' map: 'foo.js.map',
}); });
equal(file, 'foo.js.map'); equal(file, 'foo.js.map');
equal(log.match(/sourceMappingURL=/g).length, 1); equal(log.match(/sourceMappingURL=/g).length, 1);
}); });
describe('#loadTemplates', function() { describe('#loadTemplates', function () {
it('should throw on missing template', function(done) { it('should throw on missing template', function (done) {
Precompiler.loadTemplates({ files: ['foo'] }, function(err) { Precompiler.loadTemplates({ files: ['foo'] }, function (err) {
equal(err.message, 'Unable to open template file "foo"'); equal(err.message, 'Unable to open template file "foo"');
done(); done();
}); });
}); });
it('should enumerate directories by extension', function(done) { it('should enumerate directories by extension', function (done) {
Precompiler.loadTemplates( Precompiler.loadTemplates(
{ files: [__dirname + '/artifacts'], extension: 'hbs' }, { files: [__dirname + '/artifacts'], extension: 'hbs' },
function(err, opts) { function (err, opts) {
equal(opts.templates.length, 2); equal(opts.templates.length, 2);
equal(opts.templates[0].name, 'example_2'); equal(opts.templates[0].name, 'example_2');
@@ -314,10 +314,10 @@ describe('precompiler', function() {
} }
); );
}); });
it('should enumerate all templates by extension', function(done) { it('should enumerate all templates by extension', function (done) {
Precompiler.loadTemplates( Precompiler.loadTemplates(
{ files: [__dirname + '/artifacts'], extension: 'handlebars' }, { files: [__dirname + '/artifacts'], extension: 'handlebars' },
function(err, opts) { function (err, opts) {
equal(opts.templates.length, 5); equal(opts.templates.length, 5);
equal(opts.templates[0].name, 'bom'); equal(opts.templates[0].name, 'bom');
equal(opts.templates[1].name, 'empty'); equal(opts.templates[1].name, 'empty');
@@ -326,50 +326,50 @@ describe('precompiler', function() {
} }
); );
}); });
it('should handle regular expression characters in extensions', function(done) { it('should handle regular expression characters in extensions', function (done) {
Precompiler.loadTemplates( Precompiler.loadTemplates(
{ files: [__dirname + '/artifacts'], extension: 'hb(s' }, { files: [__dirname + '/artifacts'], extension: 'hb(s' },
function(err) { function (err) {
// Success is not throwing // Success is not throwing
done(err); done(err);
} }
); );
}); });
it('should handle BOM', function(done) { it('should handle BOM', function (done) {
var opts = { var opts = {
files: [__dirname + '/artifacts/bom.handlebars'], files: [__dirname + '/artifacts/bom.handlebars'],
extension: 'handlebars', extension: 'handlebars',
bom: true bom: true,
}; };
Precompiler.loadTemplates(opts, function(err, opts) { Precompiler.loadTemplates(opts, function (err, opts) {
equal(opts.templates[0].source, 'a'); equal(opts.templates[0].source, 'a');
done(err); done(err);
}); });
}); });
it('should handle different root', function(done) { it('should handle different root', function (done) {
var opts = { var opts = {
files: [__dirname + '/artifacts/empty.handlebars'], files: [__dirname + '/artifacts/empty.handlebars'],
simple: true, simple: true,
root: 'foo/' root: 'foo/',
}; };
Precompiler.loadTemplates(opts, function(err, opts) { Precompiler.loadTemplates(opts, function (err, opts) {
equal(opts.templates[0].name, __dirname + '/artifacts/empty'); equal(opts.templates[0].name, __dirname + '/artifacts/empty');
done(err); done(err);
}); });
}); });
it('should accept string inputs', function(done) { it('should accept string inputs', function (done) {
var opts = { string: '' }; var opts = { string: '' };
Precompiler.loadTemplates(opts, function(err, opts) { Precompiler.loadTemplates(opts, function (err, opts) {
equal(opts.templates[0].name, undefined); equal(opts.templates[0].name, undefined);
equal(opts.templates[0].source, ''); equal(opts.templates[0].source, '');
done(err); done(err);
}); });
}); });
it('should accept string array inputs', function(done) { it('should accept string array inputs', function (done) {
var opts = { string: ['', 'bar'], name: ['beep', 'boop'] }; var opts = { string: ['', 'bar'], name: ['beep', 'boop'] };
Precompiler.loadTemplates(opts, function(err, opts) { Precompiler.loadTemplates(opts, function (err, opts) {
equal(opts.templates[0].name, 'beep'); equal(opts.templates[0].name, 'beep');
equal(opts.templates[0].source, ''); equal(opts.templates[0].source, '');
equal(opts.templates[1].name, 'boop'); equal(opts.templates[1].name, 'boop');
@@ -377,9 +377,9 @@ describe('precompiler', function() {
done(err); done(err);
}); });
}); });
it('should accept stdin input', function(done) { it('should accept stdin input', function (done) {
var stdin = require('mock-stdin').stdin(); var stdin = require('mock-stdin').stdin();
Precompiler.loadTemplates({ string: '-' }, function(err, opts) { Precompiler.loadTemplates({ string: '-' }, function (err, opts) {
equal(opts.templates[0].source, 'foo'); equal(opts.templates[0].source, 'foo');
done(err); done(err);
}); });
@@ -387,9 +387,9 @@ describe('precompiler', function() {
stdin.send('o'); stdin.send('o');
stdin.end(); stdin.end();
}); });
it('error on name missing', function(done) { it('error on name missing', function (done) {
var opts = { string: ['', 'bar'] }; var opts = { string: ['', 'bar'] };
Precompiler.loadTemplates(opts, function(err) { Precompiler.loadTemplates(opts, function (err) {
equal( equal(
err.message, err.message,
'Number of names did not match the number of string inputs' 'Number of names did not match the number of string inputs'
@@ -398,8 +398,8 @@ describe('precompiler', function() {
}); });
}); });
it('should complete when no args are passed', function(done) { it('should complete when no args are passed', function (done) {
Precompiler.loadTemplates({}, function(err, opts) { Precompiler.loadTemplates({}, function (err, opts) {
equal(opts.templates.length, 0); equal(opts.templates.length, 0);
done(err); done(err);
}); });
+91 -99
View File
@@ -1,24 +1,24 @@
describe('Regressions', function() { describe('Regressions', function () {
it('GH-94: Cannot read property of undefined', function() { it('GH-94: Cannot read property of undefined', function () {
expectTemplate('{{#books}}{{title}}{{author.name}}{{/books}}') expectTemplate('{{#books}}{{title}}{{author.name}}{{/books}}')
.withInput({ .withInput({
books: [ books: [
{ {
title: 'The origin of species', title: 'The origin of species',
author: { author: {
name: 'Charles Darwin' name: 'Charles Darwin',
} },
}, },
{ {
title: 'Lazarillo de Tormes' title: 'Lazarillo de Tormes',
} },
] ],
}) })
.withMessage('Renders without an undefined property error') .withMessage('Renders without an undefined property error')
.toCompileTo('The origin of speciesCharles DarwinLazarillo de Tormes'); .toCompileTo('The origin of speciesCharles DarwinLazarillo de Tormes');
}); });
it("GH-150: Inverted sections print when they shouldn't", function() { 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}}';
expectTemplate(string) expectTemplate(string)
@@ -43,14 +43,14 @@ describe('Regressions', function() {
.toCompileTo(' :: set'); .toCompileTo(' :: set');
}); });
it('GH-158: Using array index twice, breaks the template', function() { it('GH-158: Using array index twice, breaks the template', function () {
expectTemplate('{{arr.[0]}}, {{arr.[1]}}') expectTemplate('{{arr.[0]}}, {{arr.[1]}}')
.withInput({ arr: [1, 2] }) .withInput({ arr: [1, 2] })
.withMessage('it works as expected') .withMessage('it works as expected')
.toCompileTo('1, 2'); .toCompileTo('1, 2');
}); });
it("bug reported by @fat where lambdas weren't being properly resolved", function() { it("bug reported by @fat where lambdas weren't being properly resolved", function () {
var string = var string =
'<strong>This is a slightly more complicated {{thing}}.</strong>.\n' + '<strong>This is a slightly more complicated {{thing}}.</strong>.\n' +
'{{! Just ignore this business. }}\n' + '{{! Just ignore this business. }}\n' +
@@ -67,17 +67,17 @@ describe('Regressions', function() {
'{{/hasThings}}'; '{{/hasThings}}';
var data = { var data = {
thing: function() { thing: function () {
return 'blah'; return 'blah';
}, },
things: [ things: [
{ className: 'one', word: '@fat' }, { className: 'one', word: '@fat' },
{ className: 'two', word: '@dhg' }, { className: 'two', word: '@dhg' },
{ className: 'three', word: '@sayrer' } { className: 'three', word: '@sayrer' },
], ],
hasThings: function() { hasThings: function () {
return true; return true;
} },
}; };
var output = var output =
@@ -89,36 +89,34 @@ describe('Regressions', function() {
'<li class=three>@sayrer</li>\n' + '<li class=three>@sayrer</li>\n' +
'</ul>.\n'; '</ul>.\n';
expectTemplate(string) expectTemplate(string).withInput(data).toCompileTo(output);
.withInput(data)
.toCompileTo(output);
}); });
it('GH-408: Multiple loops fail', function() { it('GH-408: Multiple loops fail', function () {
expectTemplate( expectTemplate(
'{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}' '{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}'
) )
.withInput([ .withInput([
{ name: 'John Doe', location: { city: 'Chicago' } }, { name: 'John Doe', location: { city: 'Chicago' } },
{ name: 'Jane Doe', location: { city: 'New York' } } { name: 'Jane Doe', location: { city: 'New York' } },
]) ])
.withMessage('It should output multiple times') .withMessage('It should output multiple times')
.toCompileTo('John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe'); .toCompileTo('John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe');
}); });
it('GS-428: Nested if else rendering', function() { it('GS-428: Nested if else rendering', function () {
var succeedingTemplate = var succeedingTemplate =
'{{#inverse}} {{#blk}} Unexpected {{/blk}} {{else}} {{#blk}} Expected {{/blk}} {{/inverse}}'; '{{#inverse}} {{#blk}} Unexpected {{/blk}} {{else}} {{#blk}} Expected {{/blk}} {{/inverse}}';
var failingTemplate = var failingTemplate =
'{{#inverse}} {{#blk}} Unexpected {{/blk}} {{else}} {{#blk}} Expected {{/blk}} {{/inverse}}'; '{{#inverse}} {{#blk}} Unexpected {{/blk}} {{else}} {{#blk}} Expected {{/blk}} {{/inverse}}';
var helpers = { var helpers = {
blk: function(block) { blk: function (block) {
return block.fn(''); return block.fn('');
}, },
inverse: function(block) { inverse: function (block) {
return block.inverse(''); return block.inverse('');
} },
}; };
expectTemplate(succeedingTemplate) expectTemplate(succeedingTemplate)
@@ -130,34 +128,30 @@ describe('Regressions', function() {
.toCompileTo(' Expected '); .toCompileTo(' Expected ');
}); });
it('GH-458: Scoped this identifier', function() { it('GH-458: Scoped this identifier', function () {
expectTemplate('{{./foo}}') expectTemplate('{{./foo}}').withInput({ foo: 'bar' }).toCompileTo('bar');
.withInput({ foo: 'bar' })
.toCompileTo('bar');
}); });
it('GH-375: Unicode line terminators', function() { it('GH-375: Unicode line terminators', function () {
expectTemplate('\u2028').toCompileTo('\u2028'); expectTemplate('\u2028').toCompileTo('\u2028');
}); });
it('GH-534: Object prototype aliases', function() { it('GH-534: Object prototype aliases', function () {
/* eslint-disable no-extend-native */ /* eslint-disable no-extend-native */
Object.prototype[0xd834] = true; Object.prototype[0xd834] = true;
expectTemplate('{{foo}}') expectTemplate('{{foo}}').withInput({ foo: 'bar' }).toCompileTo('bar');
.withInput({ foo: 'bar' })
.toCompileTo('bar');
delete Object.prototype[0xd834]; delete Object.prototype[0xd834];
/* eslint-enable no-extend-native */ /* eslint-enable no-extend-native */
}); });
it('GH-437: Matching escaping', function() { it('GH-437: Matching escaping', function () {
expectTemplate('{{{a}}').toThrow(Error, /Parse error on/); expectTemplate('{{{a}}').toThrow(Error, /Parse error on/);
expectTemplate('{{a}}}').toThrow(Error, /Parse error on/); expectTemplate('{{a}}}').toThrow(Error, /Parse error on/);
}); });
it('GH-676: Using array in escaping mustache fails', function() { it('GH-676: Using array in escaping mustache fails', function () {
var data = { arr: [1, 2] }; var data = { arr: [1, 2] };
expectTemplate('{{arr}}') expectTemplate('{{arr}}')
@@ -166,7 +160,7 @@ describe('Regressions', function() {
.toCompileTo(data.arr.toString()); .toCompileTo(data.arr.toString());
}); });
it('Mustache man page', function() { it('Mustache man page', function () {
expectTemplate( expectTemplate(
'Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}' 'Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}'
) )
@@ -174,7 +168,7 @@ describe('Regressions', function() {
name: 'Chris', name: 'Chris',
value: 10000, value: 10000,
taxed_value: 10000 - 10000 * 0.4, taxed_value: 10000 - 10000 * 0.4,
in_ca: true in_ca: true,
}) })
.withMessage('the hello world mustache example works') .withMessage('the hello world mustache example works')
.toCompileTo( .toCompileTo(
@@ -182,69 +176,67 @@ describe('Regressions', function() {
); );
}); });
it('GH-731: zero context rendering', function() { it('GH-731: zero context rendering', function () {
expectTemplate('{{#foo}} This is {{bar}} ~ {{/foo}}') expectTemplate('{{#foo}} This is {{bar}} ~ {{/foo}}')
.withInput({ .withInput({
foo: 0, foo: 0,
bar: 'OK' bar: 'OK',
}) })
.toCompileTo(' This is ~ '); .toCompileTo(' This is ~ ');
}); });
it('GH-820: zero pathed rendering', function() { it('GH-820: zero pathed rendering', function () {
expectTemplate('{{foo.bar}}') expectTemplate('{{foo.bar}}').withInput({ foo: 0 }).toCompileTo('');
.withInput({ foo: 0 })
.toCompileTo('');
}); });
it('GH-837: undefined values for helpers', function() { it('GH-837: undefined values for helpers', function () {
expectTemplate('{{str bar.baz}}') expectTemplate('{{str bar.baz}}')
.withHelpers({ .withHelpers({
str: function(value) { str: function (value) {
return value + ''; return value + '';
} },
}) })
.toCompileTo('undefined'); .toCompileTo('undefined');
}); });
it('GH-926: Depths and de-dupe', function() { it('GH-926: Depths and de-dupe', function () {
expectTemplate( expectTemplate(
'{{#if dater}}{{#each data}}{{../name}}{{/each}}{{else}}{{#each notData}}{{../name}}{{/each}}{{/if}}' '{{#if dater}}{{#each data}}{{../name}}{{/each}}{{else}}{{#each notData}}{{../name}}{{/each}}{{/if}}'
) )
.withInput({ .withInput({
name: 'foo', name: 'foo',
data: [1], data: [1],
notData: [1] notData: [1],
}) })
.toCompileTo('foo'); .toCompileTo('foo');
}); });
it('GH-1021: Each empty string key', function() { it('GH-1021: Each empty string key', function () {
expectTemplate('{{#each data}}Key: {{@key}}\n{{/each}}') expectTemplate('{{#each data}}Key: {{@key}}\n{{/each}}')
.withInput({ .withInput({
data: { data: {
'': 'foo', '': 'foo',
name: 'Chris', name: 'Chris',
value: 10000 value: 10000,
} },
}) })
.toCompileTo('Key: \nKey: name\nKey: value\n'); .toCompileTo('Key: \nKey: name\nKey: value\n');
}); });
it('GH-1054: Should handle simple safe string responses', function() { it('GH-1054: Should handle simple safe string responses', function () {
expectTemplate('{{#wrap}}{{>partial}}{{/wrap}}') expectTemplate('{{#wrap}}{{>partial}}{{/wrap}}')
.withHelpers({ .withHelpers({
wrap: function(options) { wrap: function (options) {
return new Handlebars.SafeString(options.fn()); return new Handlebars.SafeString(options.fn());
} },
}) })
.withPartials({ .withPartials({
partial: '{{#wrap}}<partial>{{/wrap}}' partial: '{{#wrap}}<partial>{{/wrap}}',
}) })
.toCompileTo('<partial>'); .toCompileTo('<partial>');
}); });
it('GH-1065: Sparse arrays', function() { it('GH-1065: Sparse arrays', function () {
var array = []; var array = [];
array[1] = 'foo'; array[1] = 'foo';
array[3] = 'bar'; array[3] = 'bar';
@@ -253,11 +245,11 @@ describe('Regressions', function() {
.toCompileTo('1foo3bar'); .toCompileTo('1foo3bar');
}); });
it('GH-1093: Undefined helper context', function() { it('GH-1093: Undefined helper context', function () {
expectTemplate('{{#each obj}}{{{helper}}}{{.}}{{/each}}') expectTemplate('{{#each obj}}{{{helper}}}{{.}}{{/each}}')
.withInput({ obj: { foo: undefined, bar: 'bat' } }) .withInput({ obj: { foo: undefined, bar: 'bat' } })
.withHelpers({ .withHelpers({
helper: function() { helper: function () {
// It's valid to execute a block against an undefined context, but // It's valid to execute a block against an undefined context, but
// helpers can not do so, so we expect to have an empty object here; // helpers can not do so, so we expect to have an empty object here;
for (var name in this) { for (var name in this) {
@@ -267,43 +259,43 @@ describe('Regressions', function() {
} }
// And to make IE happy, check for the known string as length is not enumerated. // And to make IE happy, check for the known string as length is not enumerated.
return this === 'bat' ? 'found' : 'not'; return this === 'bat' ? 'found' : 'not';
} },
}) })
.toCompileTo('notfoundbat'); .toCompileTo('notfoundbat');
}); });
it('should support multiple levels of inline partials', function() { it('should support multiple levels of inline partials', function () {
expectTemplate( expectTemplate(
'{{#> layout}}{{#*inline "subcontent"}}subcontent{{/inline}}{{/layout}}' '{{#> layout}}{{#*inline "subcontent"}}subcontent{{/inline}}{{/layout}}'
) )
.withPartials({ .withPartials({
doctype: 'doctype{{> content}}', doctype: 'doctype{{> content}}',
layout: layout:
'{{#> doctype}}{{#*inline "content"}}layout{{> subcontent}}{{/inline}}{{/doctype}}' '{{#> doctype}}{{#*inline "content"}}layout{{> subcontent}}{{/inline}}{{/doctype}}',
}) })
.toCompileTo('doctypelayoutsubcontent'); .toCompileTo('doctypelayoutsubcontent');
}); });
it('GH-1089: should support failover content in multiple levels of inline partials', function() { it('GH-1089: should support failover content in multiple levels of inline partials', function () {
expectTemplate('{{#> layout}}{{/layout}}') expectTemplate('{{#> layout}}{{/layout}}')
.withPartials({ .withPartials({
doctype: 'doctype{{> content}}', doctype: 'doctype{{> content}}',
layout: layout:
'{{#> doctype}}{{#*inline "content"}}layout{{#> subcontent}}subcontent{{/subcontent}}{{/inline}}{{/doctype}}' '{{#> doctype}}{{#*inline "content"}}layout{{#> subcontent}}subcontent{{/subcontent}}{{/inline}}{{/doctype}}',
}) })
.toCompileTo('doctypelayoutsubcontent'); .toCompileTo('doctypelayoutsubcontent');
}); });
it('GH-1099: should support greater than 3 nested levels of inline partials', function() { it('GH-1099: should support greater than 3 nested levels of inline partials', function () {
expectTemplate('{{#> layout}}Outer{{/layout}}') expectTemplate('{{#> layout}}Outer{{/layout}}')
.withPartials({ .withPartials({
layout: '{{#> inner}}Inner{{/inner}}{{> @partial-block }}', layout: '{{#> inner}}Inner{{/inner}}{{> @partial-block }}',
inner: '' inner: '',
}) })
.toCompileTo('Outer'); .toCompileTo('Outer');
}); });
it('GH-1135 : Context handling within each iteration', function() { it('GH-1135 : Context handling within each iteration', function () {
expectTemplate( expectTemplate(
'{{#each array}}\n' + '{{#each array}}\n' +
' 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}}\n' + ' 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}}\n' +
@@ -312,18 +304,18 @@ describe('Regressions', function() {
) )
.withInput({ array: [1], name: 'John' }) .withInput({ array: [1], name: 'John' })
.withHelpers({ .withHelpers({
myif: function(conditional, options) { myif: function (conditional, options) {
if (conditional) { if (conditional) {
return options.fn(this); return options.fn(this);
} else { } else {
return options.inverse(this); return options.inverse(this);
} }
} },
}) })
.toCompileTo(' 1. IF: John--\n' + ' 2. MYIF: John==\n'); .toCompileTo(' 1. IF: John--\n' + ' 2. MYIF: John==\n');
}); });
it('GH-1186: Support block params for existing programs', function() { it('GH-1186: Support block params for existing programs', function () {
expectTemplate( expectTemplate(
'{{#*inline "test"}}{{> @partial-block }}{{/inline}}' + '{{#*inline "test"}}{{> @partial-block }}{{/inline}}' +
'{{#>test }}{{#each listOne as |item|}}{{ item }}{{/each}}{{/test}}' + '{{#>test }}{{#each listOne as |item|}}{{ item }}{{/each}}{{/test}}' +
@@ -331,64 +323,64 @@ describe('Regressions', function() {
) )
.withInput({ .withInput({
listOne: ['a'], listOne: ['a'],
listTwo: ['b'] listTwo: ['b'],
}) })
.withMessage('') .withMessage('')
.toCompileTo('ab'); .toCompileTo('ab');
}); });
it('should allow hash with protected array names', function() { it('should allow hash with protected array names', function () {
var obj = { array: [1], name: 'John' }; var obj = { array: [1], name: 'John' };
var helpers = { var helpers = {
helpa: function(options) { helpa: function (options) {
return options.hash.length; return options.hash.length;
} },
}; };
shouldCompileTo('{{helpa length="foo"}}', [obj, helpers], 'foo'); shouldCompileTo('{{helpa length="foo"}}', [obj, helpers], 'foo');
}); });
it('GH-1319: "unless" breaks when "each" value equals "null"', function() { it('GH-1319: "unless" breaks when "each" value equals "null"', function () {
expectTemplate( expectTemplate(
'{{#each list}}{{#unless ./prop}}parent={{../value}} {{/unless}}{{/each}}' '{{#each list}}{{#unless ./prop}}parent={{../value}} {{/unless}}{{/each}}'
) )
.withInput({ .withInput({
value: 'parent', value: 'parent',
list: [null, 'a'] list: [null, 'a'],
}) })
.withMessage('') .withMessage('')
.toCompileTo('parent=parent parent=parent '); .toCompileTo('parent=parent parent=parent ');
}); });
it('GH-1341: 4.0.7 release breaks {{#if @partial-block}} usage', function() { it('GH-1341: 4.0.7 release breaks {{#if @partial-block}} usage', function () {
expectTemplate('template {{>partial}} template') expectTemplate('template {{>partial}} template')
.withPartials({ .withPartials({
partialWithBlock: partialWithBlock:
'{{#if @partial-block}} block {{> @partial-block}} block {{/if}}', '{{#if @partial-block}} block {{> @partial-block}} block {{/if}}',
partial: '{{#> partialWithBlock}} partial {{/partialWithBlock}}' partial: '{{#> partialWithBlock}} partial {{/partialWithBlock}}',
}) })
.toCompileTo('template block partial block template'); .toCompileTo('template block partial block template');
}); });
describe('GH-1561: 4.3.x should still work with precompiled templates from 4.0.0 <= x < 4.3.0', function() { describe('GH-1561: 4.3.x should still work with precompiled templates from 4.0.0 <= x < 4.3.0', function () {
it('should compile and execute templates', function() { it('should compile and execute templates', function () {
var newHandlebarsInstance = Handlebars.create(); var newHandlebarsInstance = Handlebars.create();
registerTemplate(newHandlebarsInstance, compiledTemplateVersion7()); registerTemplate(newHandlebarsInstance, compiledTemplateVersion7());
newHandlebarsInstance.registerHelper('loud', function(value) { newHandlebarsInstance.registerHelper('loud', function (value) {
return value.toUpperCase(); return value.toUpperCase();
}); });
var result = newHandlebarsInstance.templates['test.hbs']({ var result = newHandlebarsInstance.templates['test.hbs']({
name: 'yehuda' name: 'yehuda',
}); });
equals(result.trim(), 'YEHUDA'); equals(result.trim(), 'YEHUDA');
}); });
it('should call "helperMissing" if a helper is missing', function() { it('should call "helperMissing" if a helper is missing', function () {
var newHandlebarsInstance = Handlebars.create(); var newHandlebarsInstance = Handlebars.create();
shouldThrow( shouldThrow(
function() { function () {
registerTemplate(newHandlebarsInstance, compiledTemplateVersion7()); registerTemplate(newHandlebarsInstance, compiledTemplateVersion7());
newHandlebarsInstance.templates['test.hbs']({}); newHandlebarsInstance.templates['test.hbs']({});
}, },
@@ -397,7 +389,7 @@ describe('Regressions', function() {
); );
}); });
it('should pass "options.lookupProperty" to "lookup"-helper, even with old templates', function() { it('should pass "options.lookupProperty" to "lookup"-helper, even with old templates', function () {
var newHandlebarsInstance = Handlebars.create(); var newHandlebarsInstance = Handlebars.create();
registerTemplate( registerTemplate(
newHandlebarsInstance, newHandlebarsInstance,
@@ -409,7 +401,7 @@ describe('Regressions', function() {
expect( expect(
newHandlebarsInstance.templates['test.hbs']({ newHandlebarsInstance.templates['test.hbs']({
property: 'a', property: 'a',
test: { a: 'b' } test: { a: 'b' },
}) })
).to.equal('b'); ).to.equal('b');
}); });
@@ -423,7 +415,7 @@ describe('Regressions', function() {
function compiledTemplateVersion7() { function compiledTemplateVersion7() {
return { return {
compiler: [7, '>= 4.0.0'], compiler: [7, '>= 4.0.0'],
main: function(container, depth0, helpers, partials, data) { main: function (container, depth0, helpers, partials, data) {
return ( return (
container.escapeExpression( container.escapeExpression(
( (
@@ -438,7 +430,7 @@ describe('Regressions', function() {
) + '\n\n' ) + '\n\n'
); );
}, },
useData: true useData: true,
}; };
} }
@@ -446,7 +438,7 @@ describe('Regressions', function() {
// This is the compiled version of "{{lookup test property}}" // This is the compiled version of "{{lookup test property}}"
return { return {
compiler: [7, '>= 4.0.0'], compiler: [7, '>= 4.0.0'],
main: function(container, depth0, helpers, partials, data) { main: function (container, depth0, helpers, partials, data) {
return container.escapeExpression( return container.escapeExpression(
helpers.lookup.call( helpers.lookup.call(
depth0 != null ? depth0 : container.nullContext || {}, depth0 != null ? depth0 : container.nullContext || {},
@@ -455,45 +447,45 @@ describe('Regressions', function() {
{ {
name: 'lookup', name: 'lookup',
hash: {}, hash: {},
data: data data: data,
} }
) )
); );
}, },
useData: true useData: true,
}; };
} }
}); });
it('should allow hash with protected array names', function() { it('should allow hash with protected array names', function () {
expectTemplate('{{helpa length="foo"}}') expectTemplate('{{helpa length="foo"}}')
.withInput({ array: [1], name: 'John' }) .withInput({ array: [1], name: 'John' })
.withHelpers({ .withHelpers({
helpa: function(options) { helpa: function (options) {
return options.hash.length; return options.hash.length;
} },
}) })
.toCompileTo('foo'); .toCompileTo('foo');
}); });
describe('GH-1598: Performance degradation for partials since v4.3.0', function() { describe('GH-1598: Performance degradation for partials since v4.3.0', function () {
// Do not run test for runs without compiler // Do not run test for runs without compiler
if (!Handlebars.compile) { if (!Handlebars.compile) {
return; return;
} }
var newHandlebarsInstance; var newHandlebarsInstance;
beforeEach(function() { beforeEach(function () {
newHandlebarsInstance = Handlebars.create(); newHandlebarsInstance = Handlebars.create();
}); });
afterEach(function() { afterEach(function () {
sinon.restore(); sinon.restore();
}); });
it('should only compile global partials once', function() { it('should only compile global partials once', function () {
var templateSpy = sinon.spy(newHandlebarsInstance, 'template'); var templateSpy = sinon.spy(newHandlebarsInstance, 'template');
newHandlebarsInstance.registerPartial({ newHandlebarsInstance.registerPartial({
dude: 'I am a partial' dude: 'I am a partial',
}); });
var string = 'Dudes: {{> dude}} {{> dude}}'; var string = 'Dudes: {{> dude}} {{> dude}}';
newHandlebarsInstance.compile(string)(); // This should compile template + partial once newHandlebarsInstance.compile(string)(); // This should compile template + partial once
@@ -503,8 +495,8 @@ describe('Regressions', function() {
}); });
}); });
describe("GH-1639: TypeError: Cannot read property 'apply' of undefined\" when handlebars version > 4.6.0 (undocumented, deprecated usage)", function() { describe("GH-1639: TypeError: Cannot read property 'apply' of undefined\" when handlebars version > 4.6.0 (undocumented, deprecated usage)", function () {
it('should treat undefined helpers like non-existing helpers', function() { it('should treat undefined helpers like non-existing helpers', function () {
expectTemplate('{{foo}}') expectTemplate('{{foo}}')
.withHelper('foo', undefined) .withHelper('foo', undefined)
.withInput({ foo: 'bar' }) .withInput({ foo: 'bar' })
+3 -3
View File
@@ -1,6 +1,6 @@
if (typeof require !== 'undefined' && require.extensions['.handlebars']) { if (typeof require !== 'undefined' && require.extensions['.handlebars']) {
describe('Require', function() { describe('Require', function () {
it('Load .handlebars files with require()', function() { it('Load .handlebars files with require()', function () {
var template = require('./artifacts/example_1'); var template = require('./artifacts/example_1');
equal(template, require('./artifacts/example_1.handlebars')); equal(template, require('./artifacts/example_1.handlebars'));
@@ -10,7 +10,7 @@ if (typeof require !== 'undefined' && require.extensions['.handlebars']) {
equal(result, expected); equal(result, expected);
}); });
it('Load .hbs files with require()', function() { it('Load .hbs files with require()', function () {
var template = require('./artifacts/example_2'); var template = require('./artifacts/example_2');
equal(template, require('./artifacts/example_2.hbs')); equal(template, require('./artifacts/example_2.hbs'));
+15 -15
View File
@@ -1,53 +1,53 @@
describe('runtime', function() { describe('runtime', function () {
describe('#template', function() { describe('#template', function () {
it('should throw on invalid templates', function() { it('should throw on invalid templates', function () {
shouldThrow( shouldThrow(
function() { function () {
Handlebars.template({}); Handlebars.template({});
}, },
Error, Error,
'Unknown template object: object' 'Unknown template object: object'
); );
shouldThrow( shouldThrow(
function() { function () {
Handlebars.template(); Handlebars.template();
}, },
Error, Error,
'Unknown template object: undefined' 'Unknown template object: undefined'
); );
shouldThrow( shouldThrow(
function() { function () {
Handlebars.template(''); Handlebars.template('');
}, },
Error, Error,
'Unknown template object: string' 'Unknown template object: string'
); );
}); });
it('should throw on version mismatch', function() { it('should throw on version mismatch', function () {
shouldThrow( shouldThrow(
function() { function () {
Handlebars.template({ Handlebars.template({
main: {}, main: {},
compiler: [Handlebars.COMPILER_REVISION + 1] compiler: [Handlebars.COMPILER_REVISION + 1],
}); });
}, },
Error, Error,
/Template was precompiled with a newer version of Handlebars than the current runtime/ /Template was precompiled with a newer version of Handlebars than the current runtime/
); );
shouldThrow( shouldThrow(
function() { function () {
Handlebars.template({ Handlebars.template({
main: {}, main: {},
compiler: [Handlebars.LAST_COMPATIBLE_COMPILER_REVISION - 1] compiler: [Handlebars.LAST_COMPATIBLE_COMPILER_REVISION - 1],
}); });
}, },
Error, Error,
/Template was precompiled with an older version of Handlebars than the current runtime/ /Template was precompiled with an older version of Handlebars than the current runtime/
); );
shouldThrow( shouldThrow(
function() { function () {
Handlebars.template({ Handlebars.template({
main: {} main: {},
}); });
}, },
Error, Error,
@@ -56,12 +56,12 @@ describe('runtime', function() {
}); });
}); });
describe('#noConflict', function() { describe('#noConflict', function () {
if (!CompilerContext.browser) { if (!CompilerContext.browser) {
return; return;
} }
it('should reset on no conflict', function() { it('should reset on no conflict', function () {
var reset = Handlebars; var reset = Handlebars;
Handlebars.noConflict(); Handlebars.noConflict();
equal(Handlebars, 'no-conflict'); equal(Handlebars, 'no-conflict');
+81 -85
View File
@@ -1,25 +1,23 @@
describe('security issues', function() { describe('security issues', function () {
describe('GH-1495: Prevent Remote Code Execution via constructor', function() { describe('GH-1495: Prevent Remote Code Execution via constructor', function () {
it('should not allow constructors to be accessed', function() { it('should not allow constructors to be accessed', function () {
expectTemplate('{{lookup (lookup this "constructor") "name"}}') expectTemplate('{{lookup (lookup this "constructor") "name"}}')
.withInput({}) .withInput({})
.toCompileTo(''); .toCompileTo('');
expectTemplate('{{constructor.name}}') expectTemplate('{{constructor.name}}').withInput({}).toCompileTo('');
.withInput({})
.toCompileTo('');
}); });
it('GH-1603: should not allow constructors to be accessed (lookup via toString)', function() { it('GH-1603: should not allow constructors to be accessed (lookup via toString)', function () {
expectTemplate('{{lookup (lookup this (list "constructor")) "name"}}') expectTemplate('{{lookup (lookup this (list "constructor")) "name"}}')
.withInput({}) .withInput({})
.withHelper('list', function(element) { .withHelper('list', function (element) {
return [element]; return [element];
}) })
.toCompileTo(''); .toCompileTo('');
}); });
it('should allow the "constructor" property to be accessed if it is an "ownProperty"', function() { it('should allow the "constructor" property to be accessed if it is an "ownProperty"', function () {
expectTemplate('{{constructor.name}}') expectTemplate('{{constructor.name}}')
.withInput({ constructor: { name: 'here we go' } }) .withInput({ constructor: { name: 'here we go' } })
.toCompileTo('here we go'); .toCompileTo('here we go');
@@ -29,79 +27,79 @@ describe('security issues', function() {
.toCompileTo('here we go'); .toCompileTo('here we go');
}); });
it('should allow the "constructor" property to be accessed if it is an "own property"', function() { it('should allow the "constructor" property to be accessed if it is an "own property"', function () {
expectTemplate('{{lookup (lookup this "constructor") "name"}}') expectTemplate('{{lookup (lookup this "constructor") "name"}}')
.withInput({ constructor: { name: 'here we go' } }) .withInput({ constructor: { name: 'here we go' } })
.toCompileTo('here we go'); .toCompileTo('here we go');
}); });
}); });
describe('GH-1558: Prevent explicit call of helperMissing-helpers', function() { describe('GH-1558: Prevent explicit call of helperMissing-helpers', function () {
if (!Handlebars.compile) { if (!Handlebars.compile) {
return; return;
} }
describe('without the option "allowExplicitCallOfHelperMissing"', function() { describe('without the option "allowExplicitCallOfHelperMissing"', function () {
it('should throw an exception when calling "{{helperMissing}}" ', function() { it('should throw an exception when calling "{{helperMissing}}" ', function () {
expectTemplate('{{helperMissing}}').toThrow(Error); expectTemplate('{{helperMissing}}').toThrow(Error);
}); });
it('should throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function() { it('should throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function () {
expectTemplate('{{#helperMissing}}{{/helperMissing}}').toThrow(Error); expectTemplate('{{#helperMissing}}{{/helperMissing}}').toThrow(Error);
}); });
it('should throw an exception when calling "{{blockHelperMissing "abc" .}}" ', function() { it('should throw an exception when calling "{{blockHelperMissing "abc" .}}" ', function () {
var functionCalls = []; var functionCalls = [];
expect(function() { expect(function () {
var template = Handlebars.compile('{{blockHelperMissing "abc" .}}'); var template = Handlebars.compile('{{blockHelperMissing "abc" .}}');
template({ template({
fn: function() { fn: function () {
functionCalls.push('called'); functionCalls.push('called');
} },
}); });
}).to.throw(Error); }).to.throw(Error);
expect(functionCalls.length).to.equal(0); expect(functionCalls.length).to.equal(0);
}); });
it('should throw an exception when calling "{{#blockHelperMissing .}}{{/blockHelperMissing}}"', function() { it('should throw an exception when calling "{{#blockHelperMissing .}}{{/blockHelperMissing}}"', function () {
expectTemplate('{{#blockHelperMissing .}}{{/blockHelperMissing}}') expectTemplate('{{#blockHelperMissing .}}{{/blockHelperMissing}}')
.withInput({ .withInput({
fn: function() { fn: function () {
return 'functionInData'; return 'functionInData';
} },
}) })
.toThrow(Error); .toThrow(Error);
}); });
}); });
describe('with the option "allowCallsToHelperMissing" set to true', function() { describe('with the option "allowCallsToHelperMissing" set to true', function () {
it('should not throw an exception when calling "{{helperMissing}}" ', function() { it('should not throw an exception when calling "{{helperMissing}}" ', function () {
var template = Handlebars.compile('{{helperMissing}}'); var template = Handlebars.compile('{{helperMissing}}');
template({}, { allowCallsToHelperMissing: true }); template({}, { allowCallsToHelperMissing: true });
}); });
it('should not throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function() { it('should not throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function () {
var template = Handlebars.compile( var template = Handlebars.compile(
'{{#helperMissing}}{{/helperMissing}}' '{{#helperMissing}}{{/helperMissing}}'
); );
template({}, { allowCallsToHelperMissing: true }); template({}, { allowCallsToHelperMissing: true });
}); });
it('should not throw an exception when calling "{{blockHelperMissing "abc" .}}" ', function() { it('should not throw an exception when calling "{{blockHelperMissing "abc" .}}" ', function () {
var functionCalls = []; var functionCalls = [];
var template = Handlebars.compile('{{blockHelperMissing "abc" .}}'); var template = Handlebars.compile('{{blockHelperMissing "abc" .}}');
template( template(
{ {
fn: function() { fn: function () {
functionCalls.push('called'); functionCalls.push('called');
} },
}, },
{ allowCallsToHelperMissing: true } { allowCallsToHelperMissing: true }
); );
equals(functionCalls.length, 1); equals(functionCalls.length, 1);
}); });
it('should not throw an exception when calling "{{#blockHelperMissing .}}{{/blockHelperMissing}}"', function() { it('should not throw an exception when calling "{{#blockHelperMissing .}}{{/blockHelperMissing}}"', function () {
var template = Handlebars.compile( var template = Handlebars.compile(
'{{#blockHelperMissing true}}sdads{{/blockHelperMissing}}' '{{#blockHelperMissing true}}sdads{{/blockHelperMissing}}'
); );
@@ -110,8 +108,8 @@ describe('security issues', function() {
}); });
}); });
describe('GH-1563', function() { describe('GH-1563', function () {
it('should not allow to access constructor after overriding via __defineGetter__', function() { it('should not allow to access constructor after overriding via __defineGetter__', function () {
if ({}.__defineGetter__ == null || {}.__lookupGetter__ == null) { if ({}.__defineGetter__ == null || {}.__lookupGetter__ == null) {
return this.skip(); // Browser does not support this exploit anyway return this.skip(); // Browser does not support this exploit anyway
} }
@@ -127,7 +125,7 @@ describe('security issues', function() {
}); });
}); });
describe('GH-1595: dangerous properties', function() { describe('GH-1595: dangerous properties', function () {
var templates = [ var templates = [
'{{constructor}}', '{{constructor}}',
'{{__defineGetter__}}', '{{__defineGetter__}}',
@@ -138,53 +136,51 @@ describe('security issues', function() {
'{{lookup this "__defineGetter__"}}', '{{lookup this "__defineGetter__"}}',
'{{lookup this "__defineSetter__"}}', '{{lookup this "__defineSetter__"}}',
'{{lookup this "__lookupGetter__"}}', '{{lookup this "__lookupGetter__"}}',
'{{lookup this "__proto__"}}' '{{lookup this "__proto__"}}',
]; ];
templates.forEach(function(template) { templates.forEach(function (template) {
describe('access should be denied to ' + template, function() { describe('access should be denied to ' + template, function () {
it('by default', function() { it('by default', function () {
expectTemplate(template) expectTemplate(template).withInput({}).toCompileTo('');
.withInput({})
.toCompileTo('');
}); });
it(' with proto-access enabled', function() { it(' with proto-access enabled', function () {
expectTemplate(template) expectTemplate(template)
.withInput({}) .withInput({})
.withRuntimeOptions({ .withRuntimeOptions({
allowProtoPropertiesByDefault: true, allowProtoPropertiesByDefault: true,
allowProtoMethodsByDefault: true allowProtoMethodsByDefault: true,
}) })
.toCompileTo(''); .toCompileTo('');
}); });
}); });
}); });
}); });
describe('GH-1631: disallow access to prototype functions', function() { describe('GH-1631: disallow access to prototype functions', function () {
function TestClass() {} function TestClass() {}
TestClass.prototype.aProperty = 'propertyValue'; TestClass.prototype.aProperty = 'propertyValue';
TestClass.prototype.aMethod = function() { TestClass.prototype.aMethod = function () {
return 'returnValue'; return 'returnValue';
}; };
beforeEach(function() { beforeEach(function () {
handlebarsEnv.resetLoggedPropertyAccesses(); handlebarsEnv.resetLoggedPropertyAccesses();
}); });
afterEach(function() { afterEach(function () {
sinon.restore(); sinon.restore();
}); });
describe('control access to prototype methods via "allowedProtoMethods"', function() { describe('control access to prototype methods via "allowedProtoMethods"', function () {
checkProtoMethodAccess({}); checkProtoMethodAccess({});
describe('in compat mode', function() { describe('in compat mode', function () {
checkProtoMethodAccess({ compat: true }); checkProtoMethodAccess({ compat: true });
}); });
function checkProtoMethodAccess(compileOptions) { function checkProtoMethodAccess(compileOptions) {
it('should be prohibited by default and log a warning', function() { it('should be prohibited by default and log a warning', function () {
var spy = sinon.spy(console, 'error'); var spy = sinon.spy(console, 'error');
expectTemplate('{{aMethod}}') expectTemplate('{{aMethod}}')
@@ -196,7 +192,7 @@ describe('security issues', function() {
expect(spy.args[0][0]).to.match(/Handlebars: Access has been denied/); expect(spy.args[0][0]).to.match(/Handlebars: Access has been denied/);
}); });
it('should only log the warning once', function() { it('should only log the warning once', function () {
var spy = sinon.spy(console, 'error'); var spy = sinon.spy(console, 'error');
expectTemplate('{{aMethod}}') expectTemplate('{{aMethod}}')
@@ -213,7 +209,7 @@ describe('security issues', function() {
expect(spy.args[0][0]).to.match(/Handlebars: Access has been denied/); expect(spy.args[0][0]).to.match(/Handlebars: Access has been denied/);
}); });
it('can be allowed, which disables the warning', function() { it('can be allowed, which disables the warning', function () {
var spy = sinon.spy(console, 'error'); var spy = sinon.spy(console, 'error');
expectTemplate('{{aMethod}}') expectTemplate('{{aMethod}}')
@@ -221,89 +217,89 @@ describe('security issues', function() {
.withCompileOptions(compileOptions) .withCompileOptions(compileOptions)
.withRuntimeOptions({ .withRuntimeOptions({
allowedProtoMethods: { allowedProtoMethods: {
aMethod: true aMethod: true,
} },
}) })
.toCompileTo('returnValue'); .toCompileTo('returnValue');
expect(spy.callCount).to.equal(0); expect(spy.callCount).to.equal(0);
}); });
it('can be turned on by default, which disables the warning', function() { it('can be turned on by default, which disables the warning', function () {
var spy = sinon.spy(console, 'error'); var spy = sinon.spy(console, 'error');
expectTemplate('{{aMethod}}') expectTemplate('{{aMethod}}')
.withInput(new TestClass()) .withInput(new TestClass())
.withCompileOptions(compileOptions) .withCompileOptions(compileOptions)
.withRuntimeOptions({ .withRuntimeOptions({
allowProtoMethodsByDefault: true allowProtoMethodsByDefault: true,
}) })
.toCompileTo('returnValue'); .toCompileTo('returnValue');
expect(spy.callCount).to.equal(0); expect(spy.callCount).to.equal(0);
}); });
it('can be turned off by default, which disables the warning', function() { it('can be turned off by default, which disables the warning', function () {
var spy = sinon.spy(console, 'error'); var spy = sinon.spy(console, 'error');
expectTemplate('{{aMethod}}') expectTemplate('{{aMethod}}')
.withInput(new TestClass()) .withInput(new TestClass())
.withCompileOptions(compileOptions) .withCompileOptions(compileOptions)
.withRuntimeOptions({ .withRuntimeOptions({
allowProtoMethodsByDefault: false allowProtoMethodsByDefault: false,
}) })
.toCompileTo(''); .toCompileTo('');
expect(spy.callCount).to.equal(0); expect(spy.callCount).to.equal(0);
}); });
it('can be turned off, if turned on by default', function() { it('can be turned off, if turned on by default', function () {
expectTemplate('{{aMethod}}') expectTemplate('{{aMethod}}')
.withInput(new TestClass()) .withInput(new TestClass())
.withCompileOptions(compileOptions) .withCompileOptions(compileOptions)
.withRuntimeOptions({ .withRuntimeOptions({
allowProtoMethodsByDefault: true, allowProtoMethodsByDefault: true,
allowedProtoMethods: { allowedProtoMethods: {
aMethod: false aMethod: false,
} },
}) })
.toCompileTo(''); .toCompileTo('');
}); });
} }
it('should cause the recursive lookup by default (in "compat" mode)', function() { it('should cause the recursive lookup by default (in "compat" mode)', function () {
expectTemplate('{{#aString}}{{trim}}{{/aString}}') expectTemplate('{{#aString}}{{trim}}{{/aString}}')
.withInput({ aString: ' abc ', trim: 'trim' }) .withInput({ aString: ' abc ', trim: 'trim' })
.withCompileOptions({ compat: true }) .withCompileOptions({ compat: true })
.toCompileTo('trim'); .toCompileTo('trim');
}); });
it('should not cause the recursive lookup if allowed through options(in "compat" mode)', function() { it('should not cause the recursive lookup if allowed through options(in "compat" mode)', function () {
expectTemplate('{{#aString}}{{trim}}{{/aString}}') expectTemplate('{{#aString}}{{trim}}{{/aString}}')
.withInput({ aString: ' abc ', trim: 'trim' }) .withInput({ aString: ' abc ', trim: 'trim' })
.withCompileOptions({ compat: true }) .withCompileOptions({ compat: true })
.withRuntimeOptions({ .withRuntimeOptions({
allowedProtoMethods: { allowedProtoMethods: {
trim: true trim: true,
} },
}) })
.toCompileTo('abc'); .toCompileTo('abc');
}); });
}); });
describe('control access to prototype non-methods via "allowedProtoProperties" and "allowProtoPropertiesByDefault', function() { describe('control access to prototype non-methods via "allowedProtoProperties" and "allowProtoPropertiesByDefault', function () {
checkProtoPropertyAccess({}); checkProtoPropertyAccess({});
describe('in compat-mode', function() { describe('in compat-mode', function () {
checkProtoPropertyAccess({ compat: true }); checkProtoPropertyAccess({ compat: true });
}); });
describe('in strict-mode', function() { describe('in strict-mode', function () {
checkProtoPropertyAccess({ strict: true }); checkProtoPropertyAccess({ strict: true });
}); });
function checkProtoPropertyAccess(compileOptions) { function checkProtoPropertyAccess(compileOptions) {
it('should be prohibited by default and log a warning', function() { it('should be prohibited by default and log a warning', function () {
var spy = sinon.spy(console, 'error'); var spy = sinon.spy(console, 'error');
expectTemplate('{{aProperty}}') expectTemplate('{{aProperty}}')
@@ -315,21 +311,21 @@ describe('security issues', function() {
expect(spy.args[0][0]).to.match(/Handlebars: Access has been denied/); expect(spy.args[0][0]).to.match(/Handlebars: Access has been denied/);
}); });
it('can be explicitly prohibited by default, which disables the warning', function() { it('can be explicitly prohibited by default, which disables the warning', function () {
var spy = sinon.spy(console, 'error'); var spy = sinon.spy(console, 'error');
expectTemplate('{{aProperty}}') expectTemplate('{{aProperty}}')
.withInput(new TestClass()) .withInput(new TestClass())
.withCompileOptions(compileOptions) .withCompileOptions(compileOptions)
.withRuntimeOptions({ .withRuntimeOptions({
allowProtoPropertiesByDefault: false allowProtoPropertiesByDefault: false,
}) })
.toCompileTo(''); .toCompileTo('');
expect(spy.callCount).to.equal(0); expect(spy.callCount).to.equal(0);
}); });
it('can be turned on, which disables the warning', function() { it('can be turned on, which disables the warning', function () {
var spy = sinon.spy(console, 'error'); var spy = sinon.spy(console, 'error');
expectTemplate('{{aProperty}}') expectTemplate('{{aProperty}}')
@@ -337,63 +333,63 @@ describe('security issues', function() {
.withCompileOptions(compileOptions) .withCompileOptions(compileOptions)
.withRuntimeOptions({ .withRuntimeOptions({
allowedProtoProperties: { allowedProtoProperties: {
aProperty: true aProperty: true,
} },
}) })
.toCompileTo('propertyValue'); .toCompileTo('propertyValue');
expect(spy.callCount).to.equal(0); expect(spy.callCount).to.equal(0);
}); });
it('can be turned on by default, which disables the warning', function() { it('can be turned on by default, which disables the warning', function () {
var spy = sinon.spy(console, 'error'); var spy = sinon.spy(console, 'error');
expectTemplate('{{aProperty}}') expectTemplate('{{aProperty}}')
.withInput(new TestClass()) .withInput(new TestClass())
.withCompileOptions(compileOptions) .withCompileOptions(compileOptions)
.withRuntimeOptions({ .withRuntimeOptions({
allowProtoPropertiesByDefault: true allowProtoPropertiesByDefault: true,
}) })
.toCompileTo('propertyValue'); .toCompileTo('propertyValue');
expect(spy.callCount).to.equal(0); expect(spy.callCount).to.equal(0);
}); });
it('can be turned off, if turned on by default', function() { it('can be turned off, if turned on by default', function () {
expectTemplate('{{aProperty}}') expectTemplate('{{aProperty}}')
.withInput(new TestClass()) .withInput(new TestClass())
.withCompileOptions(compileOptions) .withCompileOptions(compileOptions)
.withRuntimeOptions({ .withRuntimeOptions({
allowProtoPropertiesByDefault: true, allowProtoPropertiesByDefault: true,
allowedProtoProperties: { allowedProtoProperties: {
aProperty: false aProperty: false,
} },
}) })
.toCompileTo(''); .toCompileTo('');
}); });
} }
}); });
describe('compatibility with old runtimes, that do not provide the function "container.lookupProperty"', function() { describe('compatibility with old runtimes, that do not provide the function "container.lookupProperty"', function () {
beforeEach(function simulateRuntimeWithoutLookupProperty() { beforeEach(function simulateRuntimeWithoutLookupProperty() {
var oldTemplateMethod = handlebarsEnv.template; var oldTemplateMethod = handlebarsEnv.template;
sinon.replace(handlebarsEnv, 'template', function(templateSpec) { sinon.replace(handlebarsEnv, 'template', function (templateSpec) {
templateSpec.main = wrapToAdjustContainer(templateSpec.main); templateSpec.main = wrapToAdjustContainer(templateSpec.main);
return oldTemplateMethod.call(this, templateSpec); return oldTemplateMethod.call(this, templateSpec);
}); });
}); });
afterEach(function() { afterEach(function () {
sinon.restore(); sinon.restore();
}); });
it('should work with simple properties', function() { it('should work with simple properties', function () {
expectTemplate('{{aProperty}}') expectTemplate('{{aProperty}}')
.withInput({ aProperty: 'propertyValue' }) .withInput({ aProperty: 'propertyValue' })
.toCompileTo('propertyValue'); .toCompileTo('propertyValue');
}); });
it('should work with Array.prototype.length', function() { it('should work with Array.prototype.length', function () {
expectTemplate('{{anArray.length}}') expectTemplate('{{anArray.length}}')
.withInput({ anArray: ['a', 'b', 'c'] }) .withInput({ anArray: ['a', 'b', 'c'] })
.toCompileTo('3'); .toCompileTo('3');
@@ -401,21 +397,21 @@ describe('security issues', function() {
}); });
}); });
describe('escapes template variables', function() { describe('escapes template variables', function () {
it('in compat mode', function() { it('in compat mode', function () {
expectTemplate("{{'a\\b'}}") expectTemplate("{{'a\\b'}}")
.withCompileOptions({ compat: true }) .withCompileOptions({ compat: true })
.withInput({ 'a\\b': 'c' }) .withInput({ 'a\\b': 'c' })
.toCompileTo('c'); .toCompileTo('c');
}); });
it('in default mode', function() { it('in default mode', function () {
expectTemplate("{{'a\\b'}}") expectTemplate("{{'a\\b'}}")
.withCompileOptions() .withCompileOptions()
.withInput({ 'a\\b': 'c' }) .withInput({ 'a\\b': 'c' })
.toCompileTo('c'); .toCompileTo('c');
}); });
it('in default mode', function() { it('in default mode', function () {
expectTemplate("{{'a\\b'}}") expectTemplate("{{'a\\b'}}")
.withCompileOptions({ strict: true }) .withCompileOptions({ strict: true })
.withInput({ 'a\\b': 'c' }) .withInput({ 'a\\b': 'c' })
+6 -6
View File
@@ -7,26 +7,26 @@ try {
/* NOP for in browser */ /* NOP for in browser */
} }
describe('source-map', function() { describe('source-map', function () {
if (!Handlebars.precompile || !SourceMap) { if (!Handlebars.precompile || !SourceMap) {
return; return;
} }
it('should safely include source map info', function() { it('should safely include source map info', function () {
var template = Handlebars.precompile('{{hello}}', { var template = Handlebars.precompile('{{hello}}', {
destName: 'dest.js', destName: 'dest.js',
srcName: 'src.hbs' srcName: 'src.hbs',
}); });
equal(!!template.code, true); equal(!!template.code, true);
equal(!!template.map, !CompilerContext.browser); equal(!!template.map, !CompilerContext.browser);
}); });
it('should map source properly', function() { it('should map source properly', function () {
var templateSource = var templateSource =
' b{{hello}} \n {{bar}}a {{#block arg hash=(subex 1 subval)}}{{/block}}', ' b{{hello}} \n {{bar}}a {{#block arg hash=(subex 1 subval)}}{{/block}}',
template = Handlebars.precompile(templateSource, { template = Handlebars.precompile(templateSource, {
destName: 'dest.js', destName: 'dest.js',
srcName: 'src.hbs' srcName: 'src.hbs',
}); });
if (template.map) { if (template.map) {
@@ -49,7 +49,7 @@ function grepLine(token, lines) {
if (column >= 0) { if (column >= 0) {
return { return {
line: i + 1, line: i + 1,
column: column column: column,
}; };
} }
} }
+6 -6
View File
@@ -1,4 +1,4 @@
describe('spec', function() { describe('spec', function () {
// NOP Under non-node environments // NOP Under non-node environments
if (typeof process === 'undefined') { if (typeof process === 'undefined') {
return; return;
@@ -7,11 +7,11 @@ describe('spec', function() {
var fs = require('fs'); var fs = require('fs');
var specDir = __dirname + '/mustache/specs/'; var specDir = __dirname + '/mustache/specs/';
var specs = fs.readdirSync(specDir).filter(name => /.*\.json$/.test(name)); var specs = fs.readdirSync(specDir).filter((name) => /.*\.json$/.test(name));
specs.forEach(function(name) { specs.forEach(function (name) {
var spec = require(specDir + name); var spec = require(specDir + name);
spec.tests.forEach(function(test) { spec.tests.forEach(function (test) {
// Our lambda implementation knowingly deviates from the optional Mustache lambda spec // Our lambda implementation knowingly deviates from the optional Mustache lambda spec
// We also do not support alternative delimiters // We also do not support alternative delimiters
if ( if (
@@ -21,7 +21,7 @@ describe('spec', function() {
// We nest the entire response from partials, not just the literals // We nest the entire response from partials, not just the literals
(name === 'partials.json' && test.name === 'Standalone Indentation') || (name === 'partials.json' && test.name === 'Standalone Indentation') ||
/\{\{=/.test(test.template) || /\{\{=/.test(test.template) ||
Object.values(test.partials || {}).some(value => /\{\{=/.test(value)) Object.values(test.partials || {}).some((value) => /\{\{=/.test(value))
) { ) {
it.skip(name + ' - ' + test.name); it.skip(name + ' - ' + test.name);
return; return;
@@ -33,7 +33,7 @@ describe('spec', function() {
/* eslint-disable-next-line no-eval */ /* eslint-disable-next-line no-eval */
data.lambda = eval('(' + data.lambda.js + ')'); data.lambda = eval('(' + data.lambda.js + ')');
} }
it(name + ' - ' + test.name, function() { it(name + ' - ' + test.name, function () {
expectTemplate(test.template) expectTemplate(test.template)
.withInput(data) .withInput(data)
.withPartials(test.partials || {}) .withPartials(test.partials || {})
+27 -27
View File
@@ -1,14 +1,14 @@
var Exception = Handlebars.Exception; var Exception = Handlebars.Exception;
describe('strict', function() { describe('strict', function () {
describe('strict mode', function() { describe('strict mode', function () {
it('should error on missing property lookup', function() { it('should error on missing property lookup', function () {
expectTemplate('{{hello}}') expectTemplate('{{hello}}')
.withCompileOptions({ strict: true }) .withCompileOptions({ strict: true })
.toThrow(Exception, /"hello" not defined in/); .toThrow(Exception, /"hello" not defined in/);
}); });
it('should error on missing child', function() { it('should error on missing child', function () {
expectTemplate('{{hello.bar}}') expectTemplate('{{hello.bar}}')
.withCompileOptions({ strict: true }) .withCompileOptions({ strict: true })
.withInput({ hello: { bar: 'foo' } }) .withInput({ hello: { bar: 'foo' } })
@@ -20,31 +20,31 @@ describe('strict', function() {
.toThrow(Exception, /"bar" not defined in/); .toThrow(Exception, /"bar" not defined in/);
}); });
it('should handle explicit undefined', function() { it('should handle explicit undefined', function () {
expectTemplate('{{hello.bar}}') expectTemplate('{{hello.bar}}')
.withCompileOptions({ strict: true }) .withCompileOptions({ strict: true })
.withInput({ hello: { bar: undefined } }) .withInput({ hello: { bar: undefined } })
.toCompileTo(''); .toCompileTo('');
}); });
it('should error on missing property lookup in known helpers mode', function() { it('should error on missing property lookup in known helpers mode', function () {
expectTemplate('{{hello}}') expectTemplate('{{hello}}')
.withCompileOptions({ .withCompileOptions({
strict: true, strict: true,
knownHelpersOnly: true knownHelpersOnly: true,
}) })
.toThrow(Exception, /"hello" not defined in/); .toThrow(Exception, /"hello" not defined in/);
}); });
it('should error on missing context', function() { it('should error on missing context', function () {
expectTemplate('{{hello}}') expectTemplate('{{hello}}')
.withCompileOptions({ strict: true }) .withCompileOptions({ strict: true })
.toThrow(Error); .toThrow(Error);
}); });
it('should error on missing data lookup', function() { it('should error on missing data lookup', function () {
var xt = expectTemplate('{{@hello}}').withCompileOptions({ var xt = expectTemplate('{{@hello}}').withCompileOptions({
strict: true strict: true,
}); });
xt.toThrow(Error); xt.toThrow(Error);
@@ -52,7 +52,7 @@ describe('strict', function() {
xt.withRuntimeOptions({ data: { hello: 'foo' } }).toCompileTo('foo'); xt.withRuntimeOptions({ data: { hello: 'foo' } }).toCompileTo('foo');
}); });
it('should not run helperMissing for helper calls', function() { it('should not run helperMissing for helper calls', function () {
expectTemplate('{{hello foo}}') expectTemplate('{{hello foo}}')
.withCompileOptions({ strict: true }) .withCompileOptions({ strict: true })
.withInput({ foo: true }) .withInput({ foo: true })
@@ -64,7 +64,7 @@ describe('strict', function() {
.toThrow(Exception, /"hello" not defined in/); .toThrow(Exception, /"hello" not defined in/);
}); });
it('should throw on ambiguous blocks', function() { it('should throw on ambiguous blocks', function () {
expectTemplate('{{#hello}}{{/hello}}') expectTemplate('{{#hello}}{{/hello}}')
.withCompileOptions({ strict: true }) .withCompileOptions({ strict: true })
.toThrow(Exception, /"hello" not defined in/); .toThrow(Exception, /"hello" not defined in/);
@@ -79,37 +79,37 @@ describe('strict', function() {
.toThrow(Exception, /"bar" not defined in/); .toThrow(Exception, /"bar" not defined in/);
}); });
it('should allow undefined parameters when passed to helpers', function() { it('should allow undefined parameters when passed to helpers', function () {
expectTemplate('{{#unless foo}}success{{/unless}}') expectTemplate('{{#unless foo}}success{{/unless}}')
.withCompileOptions({ strict: true }) .withCompileOptions({ strict: true })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should allow undefined hash when passed to helpers', function() { it('should allow undefined hash when passed to helpers', function () {
expectTemplate('{{helper value=@foo}}') expectTemplate('{{helper value=@foo}}')
.withCompileOptions({ .withCompileOptions({
strict: true strict: true,
}) })
.withHelpers({ .withHelpers({
helper: function(options) { helper: function (options) {
equals('value' in options.hash, true); equals('value' in options.hash, true);
equals(options.hash.value, undefined); equals(options.hash.value, undefined);
return 'success'; return 'success';
} },
}) })
.toCompileTo('success'); .toCompileTo('success');
}); });
it('should show error location on missing property lookup', function() { it('should show error location on missing property lookup', function () {
expectTemplate('\n\n\n {{hello}}') expectTemplate('\n\n\n {{hello}}')
.withCompileOptions({ strict: true }) .withCompileOptions({ strict: true })
.toThrow(Exception, '"hello" not defined in [object Object] - 4:5'); .toThrow(Exception, '"hello" not defined in [object Object] - 4:5');
}); });
it('should error contains correct location properties on missing property lookup', function() { it('should error contains correct location properties on missing property lookup', function () {
try { try {
var template = CompilerContext.compile('\n\n\n {{hello}}', { var template = CompilerContext.compile('\n\n\n {{hello}}', {
strict: true strict: true,
}); });
template({}); template({});
} catch (error) { } catch (error) {
@@ -121,41 +121,41 @@ describe('strict', function() {
}); });
}); });
describe('assume objects', function() { describe('assume objects', function () {
it('should ignore missing property', function() { it('should ignore missing property', function () {
expectTemplate('{{hello}}') expectTemplate('{{hello}}')
.withCompileOptions({ assumeObjects: true }) .withCompileOptions({ assumeObjects: true })
.toCompileTo(''); .toCompileTo('');
}); });
it('should ignore missing child', function() { it('should ignore missing child', function () {
expectTemplate('{{hello.bar}}') expectTemplate('{{hello.bar}}')
.withCompileOptions({ assumeObjects: true }) .withCompileOptions({ assumeObjects: true })
.withInput({ hello: {} }) .withInput({ hello: {} })
.toCompileTo(''); .toCompileTo('');
}); });
it('should error on missing object', function() { it('should error on missing object', function () {
expectTemplate('{{hello.bar}}') expectTemplate('{{hello.bar}}')
.withCompileOptions({ assumeObjects: true }) .withCompileOptions({ assumeObjects: true })
.toThrow(Error); .toThrow(Error);
}); });
it('should error on missing context', function() { it('should error on missing context', function () {
expectTemplate('{{hello}}') expectTemplate('{{hello}}')
.withCompileOptions({ assumeObjects: true }) .withCompileOptions({ assumeObjects: true })
.withInput(undefined) .withInput(undefined)
.toThrow(Error); .toThrow(Error);
}); });
it('should error on missing data lookup', function() { it('should error on missing data lookup', function () {
expectTemplate('{{@hello.bar}}') expectTemplate('{{@hello.bar}}')
.withCompileOptions({ assumeObjects: true }) .withCompileOptions({ assumeObjects: true })
.withInput(undefined) .withInput(undefined)
.toThrow(Error); .toThrow(Error);
}); });
it('should execute blockHelperMissing', function() { it('should execute blockHelperMissing', function () {
expectTemplate('{{^hello}}foo{{/hello}}') expectTemplate('{{^hello}}foo{{/hello}}')
.withCompileOptions({ assumeObjects: true }) .withCompileOptions({ assumeObjects: true })
.toCompileTo('foo'); .toCompileTo('foo');
+51 -51
View File
@@ -1,68 +1,68 @@
describe('subexpressions', function() { describe('subexpressions', function () {
it('arg-less helper', function() { it('arg-less helper', function () {
expectTemplate('{{foo (bar)}}!') expectTemplate('{{foo (bar)}}!')
.withHelpers({ .withHelpers({
foo: function(val) { foo: function (val) {
return val + val; return val + val;
}, },
bar: function() { bar: function () {
return 'LOL'; return 'LOL';
} },
}) })
.toCompileTo('LOLLOL!'); .toCompileTo('LOLLOL!');
}); });
it('helper w args', function() { it('helper w args', function () {
expectTemplate('{{blog (equal a b)}}') expectTemplate('{{blog (equal a b)}}')
.withInput({ bar: 'LOL' }) .withInput({ bar: 'LOL' })
.withHelpers({ .withHelpers({
blog: function(val) { blog: function (val) {
return 'val is ' + val; return 'val is ' + val;
}, },
equal: function(x, y) { equal: function (x, y) {
return x === y; return x === y;
} },
}) })
.toCompileTo('val is true'); .toCompileTo('val is true');
}); });
it('mixed paths and helpers', function() { it('mixed paths and helpers', function () {
expectTemplate('{{blog baz.bat (equal a b) baz.bar}}') expectTemplate('{{blog baz.bat (equal a b) baz.bar}}')
.withInput({ bar: 'LOL', baz: { bat: 'foo!', bar: 'bar!' } }) .withInput({ bar: 'LOL', baz: { bat: 'foo!', bar: 'bar!' } })
.withHelpers({ .withHelpers({
blog: function(val, that, theOther) { blog: function (val, that, theOther) {
return 'val is ' + val + ', ' + that + ' and ' + theOther; return 'val is ' + val + ', ' + that + ' and ' + theOther;
}, },
equal: function(x, y) { equal: function (x, y) {
return x === y; return x === y;
} },
}) })
.toCompileTo('val is foo!, true and bar!'); .toCompileTo('val is foo!, true and bar!');
}); });
it('supports much nesting', function() { it('supports much nesting', function () {
expectTemplate('{{blog (equal (equal true true) true)}}') expectTemplate('{{blog (equal (equal true true) true)}}')
.withInput({ bar: 'LOL' }) .withInput({ bar: 'LOL' })
.withHelpers({ .withHelpers({
blog: function(val) { blog: function (val) {
return 'val is ' + val; return 'val is ' + val;
}, },
equal: function(x, y) { equal: function (x, y) {
return x === y; return x === y;
} },
}) })
.toCompileTo('val is true'); .toCompileTo('val is true');
}); });
it('GH-800 : Complex subexpressions', function() { it('GH-800 : Complex subexpressions', function () {
var context = { a: 'a', b: 'b', c: { c: 'c' }, d: 'd', e: { e: 'e' } }; var context = { a: 'a', b: 'b', c: { c: 'c' }, d: 'd', e: { e: 'e' } };
var helpers = { var helpers = {
dash: function(a, b) { dash: function (a, b) {
return a + '-' + b; return a + '-' + b;
}, },
concat: function(a, b) { concat: function (a, b) {
return a + b; return a + b;
} },
}; };
expectTemplate("{{dash 'abc' (concat a b)}}") expectTemplate("{{dash 'abc' (concat a b)}}")
@@ -91,55 +91,55 @@ describe('subexpressions', function() {
.toCompileTo('ae-c'); .toCompileTo('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 lastOptions = null; var lastOptions = null;
var helpers = { var helpers = {
equal: function(x, y, options) { equal: function (x, y, options) {
if (!options || options === lastOptions) { if (!options || options === lastOptions) {
throw new Error('options hash was reused'); throw new Error('options hash was reused');
} }
lastOptions = options; lastOptions = options;
return x === y; return x === y;
} },
}; };
expectTemplate('{{equal (equal true true) true}}') expectTemplate('{{equal (equal true true) true}}')
.withHelpers(helpers) .withHelpers(helpers)
.toCompileTo('true'); .toCompileTo('true');
}); });
it('with hashes', function() { it('with hashes', function () {
expectTemplate("{{blog (equal (equal true true) true fun='yes')}}") expectTemplate("{{blog (equal (equal true true) true fun='yes')}}")
.withInput({ bar: 'LOL' }) .withInput({ bar: 'LOL' })
.withHelpers({ .withHelpers({
blog: function(val) { blog: function (val) {
return 'val is ' + val; return 'val is ' + val;
}, },
equal: function(x, y) { equal: function (x, y) {
return x === y; return x === y;
} },
}) })
.toCompileTo('val is true'); .toCompileTo('val is true');
}); });
it('as hashes', function() { it('as hashes', function () {
expectTemplate("{{blog fun=(equal (blog fun=1) 'val is 1')}}") expectTemplate("{{blog fun=(equal (blog fun=1) 'val is 1')}}")
.withHelpers({ .withHelpers({
blog: function(options) { blog: function (options) {
return 'val is ' + options.hash.fun; return 'val is ' + options.hash.fun;
}, },
equal: function(x, y) { equal: function (x, y) {
return x === y; return x === y;
} },
}) })
.toCompileTo('val is true'); .toCompileTo('val is true');
}); });
it('multiple subexpressions in a hash', function() { it('multiple subexpressions in a hash', function () {
expectTemplate( expectTemplate(
'{{input aria-label=(t "Name") placeholder=(t "Example User")}}' '{{input aria-label=(t "Name") placeholder=(t "Example User")}}'
) )
.withHelpers({ .withHelpers({
input: function(options) { input: function (options) {
var hash = options.hash; var hash = options.hash;
var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']); var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder); var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder);
@@ -151,25 +151,25 @@ describe('subexpressions', function() {
'" />' '" />'
); );
}, },
t: function(defaultString) { t: function (defaultString) {
return new Handlebars.SafeString(defaultString); return new Handlebars.SafeString(defaultString);
} },
}) })
.toCompileTo('<input aria-label="Name" placeholder="Example User" />'); .toCompileTo('<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 () {
expectTemplate( expectTemplate(
'{{input aria-label=(t item.field) placeholder=(t item.placeholder)}}' '{{input aria-label=(t item.field) placeholder=(t item.placeholder)}}'
) )
.withInput({ .withInput({
item: { item: {
field: 'Name', field: 'Name',
placeholder: 'Example User' placeholder: 'Example User',
} },
}) })
.withHelpers({ .withHelpers({
input: function(options) { input: function (options) {
var hash = options.hash; var hash = options.hash;
var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']); var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder); var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder);
@@ -181,37 +181,37 @@ describe('subexpressions', function() {
'" />' '" />'
); );
}, },
t: function(defaultString) { t: function (defaultString) {
return new Handlebars.SafeString(defaultString); return new Handlebars.SafeString(defaultString);
} },
}) })
.toCompileTo('<input aria-label="Name" placeholder="Example User" />'); .toCompileTo('<input aria-label="Name" placeholder="Example User" />');
}); });
it('subexpression functions on the context', function() { it('subexpression functions on the context', function () {
expectTemplate('{{foo (bar)}}!') expectTemplate('{{foo (bar)}}!')
.withInput({ .withInput({
bar: function() { bar: function () {
return 'LOL'; return 'LOL';
} },
}) })
.withHelpers({ .withHelpers({
foo: function(val) { foo: function (val) {
return val + val; return val + val;
} },
}) })
.toCompileTo('LOLLOL!'); .toCompileTo('LOLLOL!');
}); });
it("subexpressions can't just be property lookups", function() { it("subexpressions can't just be property lookups", function () {
expectTemplate('{{foo (bar)}}!') expectTemplate('{{foo (bar)}}!')
.withInput({ .withInput({
bar: 'LOL' bar: 'LOL',
}) })
.withHelpers({ .withHelpers({
foo: function(val) { foo: function (val) {
return val + val; return val + val;
} },
}) })
.toThrow(); .toThrow();
}); });
+93 -93
View File
@@ -8,7 +8,7 @@ function shouldBeToken(result, name, text) {
equals(result.text, text); equals(result.text, text);
} }
describe('Tokenizer', function() { describe('Tokenizer', function () {
if (!Handlebars.Parser) { if (!Handlebars.Parser) {
return; return;
} }
@@ -32,13 +32,13 @@ describe('Tokenizer', function() {
return out; return out;
} }
it('tokenizes a simple mustache as "OPEN ID CLOSE"', function() { it('tokenizes a simple mustache as "OPEN ID CLOSE"', function () {
var result = tokenize('{{foo}}'); var result = tokenize('{{foo}}');
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
shouldBeToken(result[1], 'ID', 'foo'); shouldBeToken(result[1], 'ID', 'foo');
}); });
it('supports unescaping with &', function() { it('supports unescaping with &', function () {
var result = tokenize('{{&bar}}'); var result = tokenize('{{&bar}}');
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
@@ -46,14 +46,14 @@ describe('Tokenizer', function() {
shouldBeToken(result[1], 'ID', 'bar'); shouldBeToken(result[1], 'ID', 'bar');
}); });
it('supports unescaping with {{{', function() { it('supports unescaping with {{{', function () {
var result = tokenize('{{{bar}}}'); var result = tokenize('{{{bar}}}');
shouldMatchTokens(result, ['OPEN_UNESCAPED', 'ID', 'CLOSE_UNESCAPED']); shouldMatchTokens(result, ['OPEN_UNESCAPED', 'ID', 'CLOSE_UNESCAPED']);
shouldBeToken(result[1], 'ID', 'bar'); shouldBeToken(result[1], 'ID', 'bar');
}); });
it('supports escaping delimiters', function() { it('supports escaping delimiters', function () {
var result = tokenize('{{foo}} \\{{bar}} {{baz}}'); var result = tokenize('{{foo}} \\{{bar}} {{baz}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -63,14 +63,14 @@ describe('Tokenizer', function() {
'CONTENT', 'CONTENT',
'OPEN', 'OPEN',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[3], 'CONTENT', ' '); shouldBeToken(result[3], 'CONTENT', ' ');
shouldBeToken(result[4], 'CONTENT', '{{bar}} '); shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
}); });
it('supports escaping multiple delimiters', function() { it('supports escaping multiple delimiters', function () {
var result = tokenize('{{foo}} \\{{bar}} \\{{baz}}'); var result = tokenize('{{foo}} \\{{bar}} \\{{baz}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -78,7 +78,7 @@ describe('Tokenizer', function() {
'CLOSE', 'CLOSE',
'CONTENT', 'CONTENT',
'CONTENT', 'CONTENT',
'CONTENT' 'CONTENT',
]); ]);
shouldBeToken(result[3], 'CONTENT', ' '); shouldBeToken(result[3], 'CONTENT', ' ');
@@ -86,7 +86,7 @@ describe('Tokenizer', function() {
shouldBeToken(result[5], 'CONTENT', '{{baz}}'); shouldBeToken(result[5], 'CONTENT', '{{baz}}');
}); });
it('supports escaping a triple stash', function() { it('supports escaping a triple stash', function () {
var result = tokenize('{{foo}} \\{{{bar}}} {{baz}}'); var result = tokenize('{{foo}} \\{{{bar}}} {{baz}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -96,13 +96,13 @@ describe('Tokenizer', function() {
'CONTENT', 'CONTENT',
'OPEN', 'OPEN',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[4], 'CONTENT', '{{{bar}}} '); shouldBeToken(result[4], 'CONTENT', '{{{bar}}} ');
}); });
it('supports escaping escape character', function() { it('supports escaping escape character', function () {
var result = tokenize('{{foo}} \\\\{{bar}} {{baz}}'); var result = tokenize('{{foo}} \\\\{{bar}} {{baz}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -115,14 +115,14 @@ describe('Tokenizer', function() {
'CONTENT', 'CONTENT',
'OPEN', 'OPEN',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[3], 'CONTENT', ' \\'); shouldBeToken(result[3], 'CONTENT', ' \\');
shouldBeToken(result[5], 'ID', 'bar'); shouldBeToken(result[5], 'ID', 'bar');
}); });
it('supports escaping multiple escape characters', function() { it('supports escaping multiple escape characters', function () {
var result = tokenize('{{foo}} \\\\{{bar}} \\\\{{baz}}'); var result = tokenize('{{foo}} \\\\{{bar}} \\\\{{baz}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -135,7 +135,7 @@ describe('Tokenizer', function() {
'CONTENT', 'CONTENT',
'OPEN', 'OPEN',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[3], 'CONTENT', ' \\'); shouldBeToken(result[3], 'CONTENT', ' \\');
@@ -144,7 +144,7 @@ describe('Tokenizer', function() {
shouldBeToken(result[9], 'ID', 'baz'); shouldBeToken(result[9], 'ID', 'baz');
}); });
it('supports escaped mustaches after escaped escape characters', function() { it('supports escaped mustaches after escaped escape characters', function () {
var result = tokenize('{{foo}} \\\\{{bar}} \\{{baz}}'); var result = tokenize('{{foo}} \\\\{{bar}} \\{{baz}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -156,7 +156,7 @@ describe('Tokenizer', function() {
'CLOSE', 'CLOSE',
'CONTENT', 'CONTENT',
'CONTENT', 'CONTENT',
'CONTENT' 'CONTENT',
]); ]);
shouldBeToken(result[3], 'CONTENT', ' \\'); shouldBeToken(result[3], 'CONTENT', ' \\');
@@ -166,7 +166,7 @@ describe('Tokenizer', function() {
shouldBeToken(result[8], 'CONTENT', '{{baz}}'); shouldBeToken(result[8], 'CONTENT', '{{baz}}');
}); });
it('supports escaped escape characters after escaped mustaches', function() { it('supports escaped escape characters after escaped mustaches', function () {
var result = tokenize('{{foo}} \\{{bar}} \\\\{{baz}}'); var result = tokenize('{{foo}} \\{{bar}} \\\\{{baz}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -177,7 +177,7 @@ describe('Tokenizer', function() {
'CONTENT', 'CONTENT',
'OPEN', 'OPEN',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[4], 'CONTENT', '{{bar}} '); shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
@@ -186,7 +186,7 @@ describe('Tokenizer', function() {
shouldBeToken(result[7], 'ID', 'baz'); shouldBeToken(result[7], 'ID', 'baz');
}); });
it('supports escaped escape character on a triple stash', function() { it('supports escaped escape character on a triple stash', function () {
var result = tokenize('{{foo}} \\\\{{{bar}}} {{baz}}'); var result = tokenize('{{foo}} \\\\{{{bar}}} {{baz}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -199,19 +199,19 @@ describe('Tokenizer', function() {
'CONTENT', 'CONTENT',
'OPEN', 'OPEN',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[3], 'CONTENT', ' \\'); shouldBeToken(result[3], 'CONTENT', ' \\');
shouldBeToken(result[5], 'ID', 'bar'); shouldBeToken(result[5], 'ID', 'bar');
}); });
it('tokenizes a simple path', function() { it('tokenizes a simple path', function () {
var result = tokenize('{{foo/bar}}'); var result = tokenize('{{foo/bar}}');
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
}); });
it('allows dot notation', function() { it('allows dot notation', function () {
var result = tokenize('{{foo.bar}}'); var result = tokenize('{{foo.bar}}');
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
@@ -222,16 +222,16 @@ describe('Tokenizer', function() {
'ID', 'ID',
'SEP', 'SEP',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
}); });
it('allows path literals with []', function() { it('allows path literals with []', function () {
var result = tokenize('{{foo.[bar]}}'); var result = tokenize('{{foo.[bar]}}');
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
}); });
it('allows multiple path literals on a line with []', function() { 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, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -243,21 +243,21 @@ describe('Tokenizer', function() {
'ID', 'ID',
'SEP', 'SEP',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
}); });
it('allows escaped literals in []', function() { it('allows escaped literals in []', function () {
var result = tokenize('{{foo.[bar\\]]}}'); var result = tokenize('{{foo.[bar\\]]}}');
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
}); });
it('tokenizes {{.}} as OPEN ID CLOSE', function() { it('tokenizes {{.}} as OPEN ID CLOSE', function () {
var result = tokenize('{{.}}'); var result = tokenize('{{.}}');
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
}); });
it('tokenizes a path as "OPEN (ID SEP)* ID CLOSE"', function() { it('tokenizes a path as "OPEN (ID SEP)* ID CLOSE"', function () {
var result = tokenize('{{../foo/bar}}'); var result = tokenize('{{../foo/bar}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -266,12 +266,12 @@ describe('Tokenizer', function() {
'ID', 'ID',
'SEP', 'SEP',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[1], 'ID', '..'); shouldBeToken(result[1], 'ID', '..');
}); });
it('tokenizes a path with .. as a parent path', function() { it('tokenizes a path with .. as a parent path', function () {
var result = tokenize('{{../foo.bar}}'); var result = tokenize('{{../foo.bar}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -280,58 +280,58 @@ describe('Tokenizer', function() {
'ID', 'ID',
'SEP', 'SEP',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[1], 'ID', '..'); shouldBeToken(result[1], 'ID', '..');
}); });
it('tokenizes a path with this/foo as OPEN ID SEP ID CLOSE', function() { 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']); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
shouldBeToken(result[1], 'ID', 'this'); shouldBeToken(result[1], 'ID', 'this');
shouldBeToken(result[3], 'ID', 'foo'); shouldBeToken(result[3], 'ID', 'foo');
}); });
it('tokenizes a simple mustache with spaces as "OPEN ID CLOSE"', function() { 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']); 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() { 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']); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'CLOSE']);
shouldBeToken(result[1], 'ID', 'foo'); shouldBeToken(result[1], 'ID', 'foo');
}); });
it('tokenizes raw content as "CONTENT"', function() { 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']); shouldMatchTokens(result, ['CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT']);
shouldBeToken(result[0], 'CONTENT', 'foo '); shouldBeToken(result[0], 'CONTENT', 'foo ');
shouldBeToken(result[4], 'CONTENT', ' baz'); shouldBeToken(result[4], 'CONTENT', ' baz');
}); });
it('tokenizes a partial as "OPEN_PARTIAL ID CLOSE"', function() { it('tokenizes a partial as "OPEN_PARTIAL ID CLOSE"', function () {
var result = tokenize('{{> foo}}'); var result = tokenize('{{> foo}}');
shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']); shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
}); });
it('tokenizes a partial with context as "OPEN_PARTIAL ID ID CLOSE"', function() { 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']); shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'ID', 'CLOSE']);
}); });
it('tokenizes a partial without spaces as "OPEN_PARTIAL ID CLOSE"', function() { 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']); shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
}); });
it('tokenizes a partial space at the }); as "OPEN_PARTIAL ID CLOSE"', function() { 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']); shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
}); });
it('tokenizes a partial space at the }); as "OPEN_PARTIAL ID CLOSE"', function() { 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, [ shouldMatchTokens(result, [
'OPEN_PARTIAL', 'OPEN_PARTIAL',
@@ -340,15 +340,15 @@ describe('Tokenizer', function() {
'ID', 'ID',
'SEP', 'SEP',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
}); });
it('tokenizes partial block declarations', function() { it('tokenizes partial block declarations', function () {
var result = tokenize('{{#> foo}}'); var result = tokenize('{{#> foo}}');
shouldMatchTokens(result, ['OPEN_PARTIAL_BLOCK', 'ID', 'CLOSE']); shouldMatchTokens(result, ['OPEN_PARTIAL_BLOCK', 'ID', 'CLOSE']);
}); });
it('tokenizes a comment as "COMMENT"', function() { 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, [ shouldMatchTokens(result, [
'CONTENT', 'CONTENT',
@@ -356,12 +356,12 @@ describe('Tokenizer', function() {
'CONTENT', 'CONTENT',
'OPEN', 'OPEN',
'ID', 'ID',
'CLOSE' '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() { 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, [ shouldMatchTokens(result, [
'CONTENT', 'CONTENT',
@@ -369,12 +369,12 @@ describe('Tokenizer', function() {
'CONTENT', 'CONTENT',
'OPEN', 'OPEN',
'ID', 'ID',
'CLOSE' '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() { it('tokenizes a block comment with whitespace as "COMMENT"', function () {
var result = tokenize( var result = tokenize(
'foo {{!-- this is a\n{{comment}}\n--}} bar {{ baz }}' 'foo {{!-- this is a\n{{comment}}\n--}} bar {{ baz }}'
); );
@@ -384,12 +384,12 @@ describe('Tokenizer', function() {
'CONTENT', 'CONTENT',
'OPEN', 'OPEN',
'ID', 'ID',
'CLOSE' '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() { 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, [ shouldMatchTokens(result, [
'OPEN_BLOCK', 'OPEN_BLOCK',
@@ -398,11 +398,11 @@ describe('Tokenizer', function() {
'CONTENT', 'CONTENT',
'OPEN_ENDBLOCK', 'OPEN_ENDBLOCK',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
}); });
it('tokenizes directives', function() { it('tokenizes directives', function () {
shouldMatchTokens(tokenize('{{#*foo}}content{{/foo}}'), [ shouldMatchTokens(tokenize('{{#*foo}}content{{/foo}}'), [
'OPEN_BLOCK', 'OPEN_BLOCK',
'ID', 'ID',
@@ -410,30 +410,30 @@ describe('Tokenizer', function() {
'CONTENT', 'CONTENT',
'OPEN_ENDBLOCK', 'OPEN_ENDBLOCK',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
shouldMatchTokens(tokenize('{{*foo}}'), ['OPEN', 'ID', 'CLOSE']); shouldMatchTokens(tokenize('{{*foo}}'), ['OPEN', 'ID', 'CLOSE']);
}); });
it('tokenizes inverse sections as "INVERSE"', function() { it('tokenizes inverse sections as "INVERSE"', function () {
shouldMatchTokens(tokenize('{{^}}'), ['INVERSE']); shouldMatchTokens(tokenize('{{^}}'), ['INVERSE']);
shouldMatchTokens(tokenize('{{else}}'), ['INVERSE']); shouldMatchTokens(tokenize('{{else}}'), ['INVERSE']);
shouldMatchTokens(tokenize('{{ else }}'), ['INVERSE']); shouldMatchTokens(tokenize('{{ else }}'), ['INVERSE']);
}); });
it('tokenizes inverse sections with ID as "OPEN_INVERSE ID CLOSE"', function() { 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']); 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() { 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']); 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() { 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']); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'CLOSE']);
shouldBeToken(result[1], 'ID', 'foo'); shouldBeToken(result[1], 'ID', 'foo');
@@ -441,37 +441,37 @@ describe('Tokenizer', function() {
shouldBeToken(result[3], 'ID', 'baz'); shouldBeToken(result[3], 'ID', 'baz');
}); });
it('tokenizes mustaches with String params as "OPEN ID ID STRING CLOSE"', function() { 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']); 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() { it('tokenizes mustaches with String params using single quotes 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']); 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() { 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']); 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() { it('tokenizes String params with escapes quotes as STRING', function () {
var result = tokenize('{{ foo "bar\\"baz" }}'); var result = tokenize('{{ foo "bar\\"baz" }}');
shouldMatchTokens(result, ['OPEN', 'ID', 'STRING', 'CLOSE']); 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() { it('tokenizes String params using single quotes with escapes quotes as STRING', function () {
var result = tokenize("{{ foo 'bar\\'baz' }}"); var result = tokenize("{{ foo 'bar\\'baz' }}");
shouldMatchTokens(result, ['OPEN', 'ID', 'STRING', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'ID', 'STRING', 'CLOSE']);
shouldBeToken(result[2], 'STRING', "bar'baz"); shouldBeToken(result[2], 'STRING', "bar'baz");
}); });
it('tokenizes numbers', function() { it('tokenizes numbers', function () {
var result = tokenize('{{ foo 1 }}'); var result = tokenize('{{ foo 1 }}');
shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
shouldBeToken(result[2], 'NUMBER', '1'); shouldBeToken(result[2], 'NUMBER', '1');
@@ -489,7 +489,7 @@ describe('Tokenizer', function() {
shouldBeToken(result[2], 'NUMBER', '-1.1'); shouldBeToken(result[2], 'NUMBER', '-1.1');
}); });
it('tokenizes booleans', function() { it('tokenizes booleans', function () {
var result = tokenize('{{ foo true }}'); var result = tokenize('{{ foo true }}');
shouldMatchTokens(result, ['OPEN', 'ID', 'BOOLEAN', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'ID', 'BOOLEAN', 'CLOSE']);
shouldBeToken(result[2], 'BOOLEAN', 'true'); shouldBeToken(result[2], 'BOOLEAN', 'true');
@@ -499,14 +499,14 @@ describe('Tokenizer', function() {
shouldBeToken(result[2], 'BOOLEAN', 'false'); shouldBeToken(result[2], 'BOOLEAN', 'false');
}); });
it('tokenizes undefined and null', function() { it('tokenizes undefined and null', function () {
var result = tokenize('{{ foo undefined null }}'); var result = tokenize('{{ foo undefined null }}');
shouldMatchTokens(result, ['OPEN', 'ID', 'UNDEFINED', 'NULL', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'ID', 'UNDEFINED', 'NULL', 'CLOSE']);
shouldBeToken(result[2], 'UNDEFINED', 'undefined'); shouldBeToken(result[2], 'UNDEFINED', 'undefined');
shouldBeToken(result[3], 'NULL', 'null'); shouldBeToken(result[3], 'NULL', 'null');
}); });
it('tokenizes hash arguments', 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']); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
@@ -518,7 +518,7 @@ describe('Tokenizer', function() {
'ID', 'ID',
'EQUALS', 'EQUALS',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
result = tokenize('{{ foo bar baz=1 }}'); result = tokenize('{{ foo bar baz=1 }}');
@@ -529,7 +529,7 @@ describe('Tokenizer', function() {
'ID', 'ID',
'EQUALS', 'EQUALS',
'NUMBER', 'NUMBER',
'CLOSE' 'CLOSE',
]); ]);
result = tokenize('{{ foo bar baz=true }}'); result = tokenize('{{ foo bar baz=true }}');
@@ -540,7 +540,7 @@ describe('Tokenizer', function() {
'ID', 'ID',
'EQUALS', 'EQUALS',
'BOOLEAN', 'BOOLEAN',
'CLOSE' 'CLOSE',
]); ]);
result = tokenize('{{ foo bar baz=false }}'); result = tokenize('{{ foo bar baz=false }}');
@@ -551,7 +551,7 @@ describe('Tokenizer', function() {
'ID', 'ID',
'EQUALS', 'EQUALS',
'BOOLEAN', 'BOOLEAN',
'CLOSE' 'CLOSE',
]); ]);
result = tokenize('{{ foo bar\n baz=bat }}'); result = tokenize('{{ foo bar\n baz=bat }}');
@@ -562,7 +562,7 @@ describe('Tokenizer', function() {
'ID', 'ID',
'EQUALS', 'EQUALS',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
result = tokenize('{{ foo bar baz="bat" }}'); result = tokenize('{{ foo bar baz="bat" }}');
@@ -573,7 +573,7 @@ describe('Tokenizer', function() {
'ID', 'ID',
'EQUALS', 'EQUALS',
'STRING', 'STRING',
'CLOSE' 'CLOSE',
]); ]);
result = tokenize('{{ foo bar baz="bat" bam=wot }}'); result = tokenize('{{ foo bar baz="bat" bam=wot }}');
@@ -587,7 +587,7 @@ describe('Tokenizer', function() {
'ID', 'ID',
'EQUALS', 'EQUALS',
'ID', 'ID',
'CLOSE' 'CLOSE',
]); ]);
result = tokenize('{{foo omg bar=baz bat="bam"}}'); result = tokenize('{{foo omg bar=baz bat="bam"}}');
@@ -601,12 +601,12 @@ describe('Tokenizer', function() {
'ID', 'ID',
'EQUALS', 'EQUALS',
'STRING', 'STRING',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[2], 'ID', 'omg'); shouldBeToken(result[2], 'ID', 'omg');
}); });
it('tokenizes special @ identifiers', function() { it('tokenizes special @ identifiers', function () {
var result = tokenize('{{ @foo }}'); var result = tokenize('{{ @foo }}');
shouldMatchTokens(result, ['OPEN', 'DATA', 'ID', 'CLOSE']); shouldMatchTokens(result, ['OPEN', 'DATA', 'ID', 'CLOSE']);
shouldBeToken(result[2], 'ID', 'foo'); shouldBeToken(result[2], 'ID', 'foo');
@@ -623,20 +623,20 @@ describe('Tokenizer', function() {
'EQUALS', 'EQUALS',
'DATA', 'DATA',
'ID', 'ID',
'CLOSE' '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() { 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() { 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() { it('tokenizes subexpressions', function () {
var result = tokenize('{{foo (bar)}}'); var result = tokenize('{{foo (bar)}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -644,7 +644,7 @@ describe('Tokenizer', function() {
'OPEN_SEXPR', 'OPEN_SEXPR',
'ID', 'ID',
'CLOSE_SEXPR', 'CLOSE_SEXPR',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[1], 'ID', 'foo'); shouldBeToken(result[1], 'ID', 'foo');
shouldBeToken(result[3], 'ID', 'bar'); shouldBeToken(result[3], 'ID', 'bar');
@@ -657,14 +657,14 @@ describe('Tokenizer', function() {
'ID', 'ID',
'ID', 'ID',
'CLOSE_SEXPR', 'CLOSE_SEXPR',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[1], 'ID', 'foo'); shouldBeToken(result[1], 'ID', 'foo');
shouldBeToken(result[3], 'ID', 'a-x'); shouldBeToken(result[3], 'ID', 'a-x');
shouldBeToken(result[4], 'ID', 'b-y'); shouldBeToken(result[4], 'ID', 'b-y');
}); });
it('tokenizes nested subexpressions', function() { it('tokenizes nested subexpressions', function () {
var result = tokenize('{{foo (bar (lol rofl)) (baz)}}'); var result = tokenize('{{foo (bar (lol rofl)) (baz)}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN', 'OPEN',
@@ -679,7 +679,7 @@ describe('Tokenizer', function() {
'OPEN_SEXPR', 'OPEN_SEXPR',
'ID', 'ID',
'CLOSE_SEXPR', 'CLOSE_SEXPR',
'CLOSE' 'CLOSE',
]); ]);
shouldBeToken(result[3], 'ID', 'bar'); shouldBeToken(result[3], 'ID', 'bar');
shouldBeToken(result[5], 'ID', 'lol'); shouldBeToken(result[5], 'ID', 'lol');
@@ -687,7 +687,7 @@ describe('Tokenizer', function() {
shouldBeToken(result[10], 'ID', 'baz'); shouldBeToken(result[10], 'ID', 'baz');
}); });
it('tokenizes nested subexpressions: literals', function() { it('tokenizes nested subexpressions: literals', function () {
var result = tokenize( var result = tokenize(
'{{foo (bar (lol true) false) (baz 1) (blah \'b\') (blorg "c")}}' '{{foo (bar (lol true) false) (baz 1) (blah \'b\') (blorg "c")}}'
); );
@@ -714,11 +714,11 @@ describe('Tokenizer', function() {
'ID', 'ID',
'STRING', 'STRING',
'CLOSE_SEXPR', 'CLOSE_SEXPR',
'CLOSE' 'CLOSE',
]); ]);
}); });
it('tokenizes block params', function() { it('tokenizes block params', function () {
var result = tokenize('{{#foo as |bar|}}'); var result = tokenize('{{#foo as |bar|}}');
shouldMatchTokens(result, [ shouldMatchTokens(result, [
'OPEN_BLOCK', 'OPEN_BLOCK',
@@ -726,7 +726,7 @@ describe('Tokenizer', function() {
'OPEN_BLOCK_PARAMS', 'OPEN_BLOCK_PARAMS',
'ID', 'ID',
'CLOSE_BLOCK_PARAMS', 'CLOSE_BLOCK_PARAMS',
'CLOSE' 'CLOSE',
]); ]);
result = tokenize('{{#foo as |bar baz|}}'); result = tokenize('{{#foo as |bar baz|}}');
@@ -737,7 +737,7 @@ describe('Tokenizer', function() {
'ID', 'ID',
'ID', 'ID',
'CLOSE_BLOCK_PARAMS', 'CLOSE_BLOCK_PARAMS',
'CLOSE' 'CLOSE',
]); ]);
result = tokenize('{{#foo as | bar baz |}}'); result = tokenize('{{#foo as | bar baz |}}');
@@ -748,7 +748,7 @@ describe('Tokenizer', function() {
'ID', 'ID',
'ID', 'ID',
'CLOSE_BLOCK_PARAMS', 'CLOSE_BLOCK_PARAMS',
'CLOSE' 'CLOSE',
]); ]);
result = tokenize('{{#foo as as | bar baz |}}'); result = tokenize('{{#foo as as | bar baz |}}');
@@ -760,7 +760,7 @@ describe('Tokenizer', function() {
'ID', 'ID',
'ID', 'ID',
'CLOSE_BLOCK_PARAMS', 'CLOSE_BLOCK_PARAMS',
'CLOSE' 'CLOSE',
]); ]);
result = tokenize('{{else foo as |bar baz|}}'); result = tokenize('{{else foo as |bar baz|}}');
@@ -771,11 +771,11 @@ describe('Tokenizer', function() {
'ID', 'ID',
'ID', 'ID',
'CLOSE_BLOCK_PARAMS', 'CLOSE_BLOCK_PARAMS',
'CLOSE' 'CLOSE',
]); ]);
}); });
it('tokenizes raw blocks', function() { it('tokenizes raw blocks', function () {
var result = tokenize( var result = tokenize(
'{{{{a}}}} abc {{{{/a}}}} aaa {{{{a}}}} abc {{{{/a}}}}' '{{{{a}}}} abc {{{{/a}}}} aaa {{{{a}}}} abc {{{{/a}}}}'
); );
@@ -790,7 +790,7 @@ describe('Tokenizer', function() {
'ID', 'ID',
'CLOSE_RAW_BLOCK', 'CLOSE_RAW_BLOCK',
'CONTENT', 'CONTENT',
'END_RAW_BLOCK' 'END_RAW_BLOCK',
]); ]);
}); });
}); });
+16 -16
View File
@@ -1,6 +1,6 @@
describe('utils', function() { describe('utils', function () {
describe('#SafeString', function() { describe('#SafeString', function () {
it('constructing a safestring from a string and checking its type', function() { it('constructing a safestring from a string and checking its type', function () {
var safe = new Handlebars.SafeString('testing 1, 2, 3'); var safe = new Handlebars.SafeString('testing 1, 2, 3');
if (!(safe instanceof Handlebars.SafeString)) { if (!(safe instanceof Handlebars.SafeString)) {
throw new Error('Must be instance of SafeString'); throw new Error('Must be instance of SafeString');
@@ -12,7 +12,7 @@ describe('utils', function() {
); );
}); });
it('it should not escape SafeString properties', function() { it('it should not escape SafeString properties', function () {
var name = new Handlebars.SafeString('<em>Sean O&#x27;Malley</em>'); var name = new Handlebars.SafeString('<em>Sean O&#x27;Malley</em>');
expectTemplate('{{name}}') expectTemplate('{{name}}')
@@ -21,26 +21,26 @@ describe('utils', function() {
}); });
}); });
describe('#escapeExpression', function() { describe('#escapeExpression', function () {
it('should escape html', function() { it('should escape html', function () {
equals( equals(
Handlebars.Utils.escapeExpression('foo<&"\'>'), Handlebars.Utils.escapeExpression('foo<&"\'>'),
'foo&lt;&amp;&quot;&#x27;&gt;' 'foo&lt;&amp;&quot;&#x27;&gt;'
); );
equals(Handlebars.Utils.escapeExpression('foo='), 'foo&#x3D;'); equals(Handlebars.Utils.escapeExpression('foo='), 'foo&#x3D;');
}); });
it('should not escape SafeString', function() { it('should not escape SafeString', function () {
var string = new Handlebars.SafeString('foo<&"\'>'); var string = new Handlebars.SafeString('foo<&"\'>');
equals(Handlebars.Utils.escapeExpression(string), 'foo<&"\'>'); equals(Handlebars.Utils.escapeExpression(string), 'foo<&"\'>');
var obj = { var obj = {
toHTML: function() { toHTML: function () {
return 'foo<&"\'>'; return 'foo<&"\'>';
} },
}; };
equals(Handlebars.Utils.escapeExpression(obj), 'foo<&"\'>'); equals(Handlebars.Utils.escapeExpression(obj), 'foo<&"\'>');
}); });
it('should handle falsy', function() { it('should handle falsy', function () {
equals(Handlebars.Utils.escapeExpression(''), ''); equals(Handlebars.Utils.escapeExpression(''), '');
equals(Handlebars.Utils.escapeExpression(undefined), ''); equals(Handlebars.Utils.escapeExpression(undefined), '');
equals(Handlebars.Utils.escapeExpression(null), ''); equals(Handlebars.Utils.escapeExpression(null), '');
@@ -48,14 +48,14 @@ describe('utils', function() {
equals(Handlebars.Utils.escapeExpression(false), 'false'); equals(Handlebars.Utils.escapeExpression(false), 'false');
equals(Handlebars.Utils.escapeExpression(0), '0'); equals(Handlebars.Utils.escapeExpression(0), '0');
}); });
it('should handle empty objects', function() { it('should handle empty objects', function () {
equals(Handlebars.Utils.escapeExpression({}), {}.toString()); equals(Handlebars.Utils.escapeExpression({}), {}.toString());
equals(Handlebars.Utils.escapeExpression([]), [].toString()); equals(Handlebars.Utils.escapeExpression([]), [].toString());
}); });
}); });
describe('#isEmpty', function() { describe('#isEmpty', function () {
it('should not be empty', function() { it('should not be empty', function () {
equals(Handlebars.Utils.isEmpty(undefined), true); equals(Handlebars.Utils.isEmpty(undefined), true);
equals(Handlebars.Utils.isEmpty(null), true); equals(Handlebars.Utils.isEmpty(null), true);
equals(Handlebars.Utils.isEmpty(false), true); equals(Handlebars.Utils.isEmpty(false), true);
@@ -63,7 +63,7 @@ describe('utils', function() {
equals(Handlebars.Utils.isEmpty([]), true); equals(Handlebars.Utils.isEmpty([]), true);
}); });
it('should be empty', function() { it('should be empty', function () {
equals(Handlebars.Utils.isEmpty(0), false); equals(Handlebars.Utils.isEmpty(0), false);
equals(Handlebars.Utils.isEmpty([1]), false); equals(Handlebars.Utils.isEmpty([1]), false);
equals(Handlebars.Utils.isEmpty('foo'), false); equals(Handlebars.Utils.isEmpty('foo'), false);
@@ -71,8 +71,8 @@ describe('utils', function() {
}); });
}); });
describe('#extend', function() { describe('#extend', function () {
it('should ignore prototype values', function() { it('should ignore prototype values', function () {
function A() { function A() {
this.a = 1; this.a = 1;
} }
+13 -23
View File
@@ -1,32 +1,22 @@
describe('whitespace control', function() { describe('whitespace control', function () {
it('should strip whitespace around mustache calls', function() { it('should strip whitespace around mustache calls', function () {
var hash = { foo: 'bar<' }; var hash = { foo: 'bar<' };
expectTemplate(' {{~foo~}} ') expectTemplate(' {{~foo~}} ').withInput(hash).toCompileTo('bar&lt;');
.withInput(hash)
.toCompileTo('bar&lt;');
expectTemplate(' {{~foo}} ') expectTemplate(' {{~foo}} ').withInput(hash).toCompileTo('bar&lt; ');
.withInput(hash)
.toCompileTo('bar&lt; ');
expectTemplate(' {{foo~}} ') expectTemplate(' {{foo~}} ').withInput(hash).toCompileTo(' bar&lt;');
.withInput(hash)
.toCompileTo(' bar&lt;');
expectTemplate(' {{~&foo~}} ') expectTemplate(' {{~&foo~}} ').withInput(hash).toCompileTo('bar<');
.withInput(hash)
.toCompileTo('bar<');
expectTemplate(' {{~{foo}~}} ') expectTemplate(' {{~{foo}~}} ').withInput(hash).toCompileTo('bar<');
.withInput(hash)
.toCompileTo('bar<');
expectTemplate('1\n{{foo~}} \n\n 23\n{{bar}}4').toCompileTo('1\n23\n4'); expectTemplate('1\n{{foo~}} \n\n 23\n{{bar}}4').toCompileTo('1\n23\n4');
}); });
describe('blocks', function() { describe('blocks', function () {
it('should strip whitespace around simple block calls', function() { it('should strip whitespace around simple block calls', function () {
var hash = { foo: 'bar<' }; var hash = { foo: 'bar<' };
expectTemplate(' {{~#if foo~}} bar {{~/if~}} ') expectTemplate(' {{~#if foo~}} bar {{~/if~}} ')
@@ -54,7 +44,7 @@ describe('whitespace control', function() {
.toCompileTo(' abara '); .toCompileTo(' abara ');
}); });
it('should strip whitespace around inverse block calls', function() { it('should strip whitespace around inverse block calls', function () {
expectTemplate(' {{~^if foo~}} bar {{~/if~}} ').toCompileTo('bar'); expectTemplate(' {{~^if foo~}} bar {{~/if~}} ').toCompileTo('bar');
expectTemplate(' {{^if foo~}} bar {{/if~}} ').toCompileTo(' bar '); expectTemplate(' {{^if foo~}} bar {{/if~}} ').toCompileTo(' bar ');
@@ -68,7 +58,7 @@ describe('whitespace control', function() {
).toCompileTo('bar'); ).toCompileTo('bar');
}); });
it('should strip whitespace around complex block calls', function() { it('should strip whitespace around complex block calls', function () {
var hash = { foo: 'bar<' }; var hash = { foo: 'bar<' };
expectTemplate('{{#if foo~}} bar {{~^~}} baz {{~/if}}') expectTemplate('{{#if foo~}} bar {{~^~}} baz {{~/if}}')
@@ -127,7 +117,7 @@ describe('whitespace control', function() {
}); });
}); });
it('should strip whitespace around partials', function() { it('should strip whitespace around partials', function () {
expectTemplate('foo {{~> dude~}} ') expectTemplate('foo {{~> dude~}} ')
.withPartials({ dude: 'bar' }) .withPartials({ dude: 'bar' })
.toCompileTo('foobar'); .toCompileTo('foobar');
@@ -149,7 +139,7 @@ describe('whitespace control', function() {
.toCompileTo('foo\n bar'); .toCompileTo('foo\n bar');
}); });
it('should only strip whitespace once', function() { it('should only strip whitespace once', function () {
expectTemplate(' {{~foo~}} {{foo}} {{foo}} ') expectTemplate(' {{~foo~}} {{foo}} {{foo}} ')
.withInput({ foo: 'bar' }) .withInput({ foo: 'bar' })
.toCompileTo('barbar bar '); .toCompileTo('barbar bar ');
+2 -2
View File
@@ -3,6 +3,6 @@ module.exports = {
'no-process-env': 'off', 'no-process-env': 'off',
'prefer-const': 'warn', 'prefer-const': 'warn',
'compat/compat': 'off', 'compat/compat': 'off',
'dot-notation': ['error', { allowKeywords: true }] 'dot-notation': ['error', { allowKeywords: true }],
} },
}; };
+5 -5
View File
@@ -1,14 +1,14 @@
const metrics = require('../tests/bench'); const metrics = require('../tests/bench');
const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task'); const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task');
module.exports = function(grunt) { module.exports = function (grunt) {
const registerAsyncTask = createRegisterAsyncTaskFn(grunt); const registerAsyncTask = createRegisterAsyncTaskFn(grunt);
registerAsyncTask('metrics', function() { registerAsyncTask('metrics', function () {
const onlyExecuteName = grunt.option('name'); const onlyExecuteName = grunt.option('name');
const events = {}; const events = {};
const promises = Object.keys(metrics).map(async name => { const promises = Object.keys(metrics).map(async (name) => {
if (/^_/.test(name)) { if (/^_/.test(name)) {
return; return;
} }
@@ -16,8 +16,8 @@ module.exports = function(grunt) {
return; return;
} }
return new Promise(resolve => { return new Promise((resolve) => {
metrics[name](grunt, function(data) { metrics[name](grunt, function (data) {
events[name] = data; events[name] = data;
resolve(); resolve();
}); });
+6 -6
View File
@@ -3,7 +3,7 @@ const git = require('./util/git');
const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task'); const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task');
const semver = require('semver'); const semver = require('semver');
module.exports = function(grunt) { module.exports = function (grunt) {
const registerAsyncTask = createRegisterAsyncTaskFn(grunt); const registerAsyncTask = createRegisterAsyncTaskFn(grunt);
registerAsyncTask('publish-to-aws', async () => { registerAsyncTask('publish-to-aws', async () => {
@@ -48,7 +48,7 @@ module.exports = function(grunt) {
} }
async function publish(suffixes) { async function publish(suffixes) {
const publishPromises = suffixes.map(suffix => publishSuffix(suffix)); const publishPromises = suffixes.map((suffix) => publishSuffix(suffix));
return Promise.all(publishPromises); return Promise.all(publishPromises);
} }
@@ -57,9 +57,9 @@ module.exports = function(grunt) {
'handlebars.js', 'handlebars.js',
'handlebars.min.js', 'handlebars.min.js',
'handlebars.runtime.js', 'handlebars.runtime.js',
'handlebars.runtime.min.js' 'handlebars.runtime.min.js',
]; ];
const publishPromises = filenames.map(async filename => { const publishPromises = filenames.map(async (filename) => {
const nameInBucket = getNameInBucket(filename, suffix); const nameInBucket = getNameInBucket(filename, suffix);
const localFile = getLocalFile(filename); const localFile = getLocalFile(filename);
await uploadToBucket(localFile, nameInBucket); await uploadToBucket(localFile, nameInBucket);
@@ -75,7 +75,7 @@ module.exports = function(grunt) {
const uploadParams = { const uploadParams = {
Bucket: bucket, Bucket: bucket,
Key: nameInBucket, Key: nameInBucket,
Body: grunt.file.read(localFile) Body: grunt.file.read(localFile),
}; };
return s3PutObject(uploadParams); return s3PutObject(uploadParams);
} }
@@ -84,7 +84,7 @@ module.exports = function(grunt) {
function s3PutObject(uploadParams) { function s3PutObject(uploadParams) {
const s3 = new AWS.S3(); const s3 = new AWS.S3();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
s3.putObject(uploadParams, err => { s3.putObject(uploadParams, (err) => {
if (err != null) { if (err != null) {
return reject(err); return reject(err);
} }
+36 -36
View File
@@ -11,47 +11,47 @@ const testCases = [
{ {
binInputParameters: ['-a', 'spec/artifacts/empty.handlebars'], binInputParameters: ['-a', 'spec/artifacts/empty.handlebars'],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.amd.js' expectedOutputSpec: './spec/expected/empty.amd.js',
}, },
{ {
binInputParameters: [ binInputParameters: [
'-a', '-a',
'-f', '-f',
'TEST_OUTPUT', 'TEST_OUTPUT',
'spec/artifacts/empty.handlebars' 'spec/artifacts/empty.handlebars',
], ],
outputLocation: 'TEST_OUTPUT', outputLocation: 'TEST_OUTPUT',
expectedOutputSpec: './spec/expected/empty.amd.js' expectedOutputSpec: './spec/expected/empty.amd.js',
}, },
{ {
binInputParameters: [ binInputParameters: [
'-a', '-a',
'-n', '-n',
'CustomNamespace.templates', 'CustomNamespace.templates',
'spec/artifacts/empty.handlebars' 'spec/artifacts/empty.handlebars',
], ],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.amd.namespace.js' expectedOutputSpec: './spec/expected/empty.amd.namespace.js',
}, },
{ {
binInputParameters: [ binInputParameters: [
'-a', '-a',
'--namespace', '--namespace',
'CustomNamespace.templates', 'CustomNamespace.templates',
'spec/artifacts/empty.handlebars' 'spec/artifacts/empty.handlebars',
], ],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.amd.namespace.js' expectedOutputSpec: './spec/expected/empty.amd.namespace.js',
}, },
{ {
binInputParameters: ['-a', '-s', 'spec/artifacts/empty.handlebars'], binInputParameters: ['-a', '-s', 'spec/artifacts/empty.handlebars'],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.amd.simple.js' expectedOutputSpec: './spec/expected/empty.amd.simple.js',
}, },
{ {
binInputParameters: ['-a', '-m', 'spec/artifacts/empty.handlebars'], binInputParameters: ['-a', '-m', 'spec/artifacts/empty.handlebars'],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.amd.min.js' expectedOutputSpec: './spec/expected/empty.amd.min.js',
}, },
{ {
binInputParameters: [ binInputParameters: [
@@ -61,44 +61,44 @@ const testCases = [
'someHelper', 'someHelper',
'-k', '-k',
'anotherHelper', 'anotherHelper',
'-o' '-o',
], ],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/non.empty.amd.known.helper.js' expectedOutputSpec: './spec/expected/non.empty.amd.known.helper.js',
}, },
{ {
binInputParameters: ['--help'], binInputParameters: ['--help'],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/help.menu.txt' expectedOutputSpec: './spec/expected/help.menu.txt',
}, },
{ {
binInputParameters: ['-v'], binInputParameters: ['-v'],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutput: require('../package.json').version expectedOutput: require('../package.json').version,
}, },
{ {
binInputParameters: [ binInputParameters: [
'-a', '-a',
'-e', '-e',
'hbs', 'hbs',
'./spec/artifacts/non.default.extension.hbs' './spec/artifacts/non.default.extension.hbs',
], ],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/non.default.extension.amd.js' expectedOutputSpec: './spec/expected/non.default.extension.amd.js',
}, },
{ {
binInputParameters: [ binInputParameters: [
'-a', '-a',
'-p', '-p',
'./spec/artifacts/partial.template.handlebars' './spec/artifacts/partial.template.handlebars',
], ],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/partial.template.js' expectedOutputSpec: './spec/expected/partial.template.js',
}, },
{ {
binInputParameters: ['spec/artifacts/empty.handlebars', '-c'], binInputParameters: ['spec/artifacts/empty.handlebars', '-c'],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.common.js' expectedOutputSpec: './spec/expected/empty.common.js',
}, },
{ {
binInputParameters: [ binInputParameters: [
@@ -106,30 +106,30 @@ const testCases = [
'spec/artifacts/empty.handlebars', 'spec/artifacts/empty.handlebars',
'-a', '-a',
'-n', '-n',
'someNameSpace' 'someNameSpace',
], ],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/namespace.amd.js' expectedOutputSpec: './spec/expected/namespace.amd.js',
}, },
{ {
binInputParameters: [ binInputParameters: [
'spec/artifacts/empty.handlebars', 'spec/artifacts/empty.handlebars',
'-h', '-h',
'some-path/', 'some-path/',
'-a' '-a',
], ],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/handlebar.path.amd.js' expectedOutputSpec: './spec/expected/handlebar.path.amd.js',
}, },
{ {
binInputParameters: [ binInputParameters: [
'spec/artifacts/partial.template.handlebars', 'spec/artifacts/partial.template.handlebars',
'-r', '-r',
'spec', 'spec',
'-a' '-a',
], ],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.root.amd.js' expectedOutputSpec: './spec/expected/empty.root.amd.js',
}, },
{ {
binInputParameters: [ binInputParameters: [
@@ -141,10 +141,10 @@ const testCases = [
'firstTemplate', 'firstTemplate',
'-N', '-N',
'secondTemplate', 'secondTemplate',
'-a' '-a',
], ],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.name.amd.js' expectedOutputSpec: './spec/expected/empty.name.amd.js',
}, },
{ {
binInputParameters: [ binInputParameters: [
@@ -155,36 +155,36 @@ const testCases = [
'-N', '-N',
'test', 'test',
'--map', '--map',
'./spec/tmp/source.map.amd.txt' './spec/tmp/source.map.amd.txt',
], ],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/source.map.amd.js' expectedOutputSpec: './spec/expected/source.map.amd.js',
}, },
{ {
binInputParameters: ['./spec/artifacts/bom.handlebars', '-b', '-a'], binInputParameters: ['./spec/artifacts/bom.handlebars', '-b', '-a'],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/bom.amd.js' expectedOutputSpec: './spec/expected/bom.amd.js',
}, },
// Issue #1673 // Issue #1673
{ {
binInputParameters: [ binInputParameters: [
'--amd', '--amd',
'--no-amd', '--no-amd',
'spec/artifacts/empty.handlebars' 'spec/artifacts/empty.handlebars',
], ],
outputLocation: 'stdout', outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.common.js' expectedOutputSpec: './spec/expected/empty.common.js',
} },
]; ];
module.exports = function(grunt) { module.exports = function (grunt) {
grunt.registerTask('test:bin', function() { grunt.registerTask('test:bin', function () {
testCases.forEach( testCases.forEach(
({ ({
binInputParameters, binInputParameters,
outputLocation, outputLocation,
expectedOutputSpec, expectedOutputSpec,
expectedOutput expectedOutput,
}) => { }) => {
const stdout = executeBinHandlebars(...binInputParameters); const stdout = executeBinHandlebars(...binInputParameters);
@@ -205,7 +205,7 @@ module.exports = function(grunt) {
expect(normalizedOutput).not.to.be.differentFrom( expect(normalizedOutput).not.to.be.differentFrom(
normalizedExpectedOutput, normalizedExpectedOutput,
{ {
relaxedSpace: true relaxedSpace: true,
} }
); );
} }
+2 -2
View File
@@ -2,7 +2,7 @@ const { execNodeJsScriptWithInheritedOutput } = require('./util/exec-file');
const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task'); const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task');
const nodeJs = process.argv0; const nodeJs = process.argv0;
module.exports = function(grunt) { module.exports = function (grunt) {
const registerAsyncTask = createRegisterAsyncTaskFn(grunt); const registerAsyncTask = createRegisterAsyncTaskFn(grunt);
registerAsyncTask('test:mocha', async () => registerAsyncTask('test:mocha', async () =>
@@ -12,7 +12,7 @@ module.exports = function(grunt) {
registerAsyncTask('test:cov', async () => registerAsyncTask('test:cov', async () =>
execNodeJsScriptWithInheritedOutput('node_modules/nyc/bin/nyc', [ execNodeJsScriptWithInheritedOutput('node_modules/nyc/bin/nyc', [
nodeJs, nodeJs,
'./spec/env/runner.js' './spec/env/runner.js',
]) ])
); );
+2 -2
View File
@@ -1,5 +1,5 @@
module.exports = { module.exports = {
env: { env: {
mocha: true mocha: true,
} },
}; };
+17 -17
View File
@@ -14,8 +14,8 @@ const remoteDir = path.join(tmpDir, 'remote-repo');
const cloneDir = path.join(tmpDir, 'clone-repo'); const cloneDir = path.join(tmpDir, 'clone-repo');
const oldCwd = process.cwd(); const oldCwd = process.cwd();
describe('utils/git', function() { describe('utils/git', function () {
beforeEach(async function() { beforeEach(async function () {
await fs.remove(tmpDir); await fs.remove(tmpDir);
await createRepositoryThatActsAsRemote(); await createRepositoryThatActsAsRemote();
process.chdir(tmpDir); process.chdir(tmpDir);
@@ -33,12 +33,12 @@ describe('utils/git', function() {
await git.commit('commit message'); await git.commit('commit message');
} }
afterEach(function() { afterEach(function () {
process.chdir(oldCwd); process.chdir(oldCwd);
}); });
describe('the "remotes"-function', function() { describe('the "remotes"-function', function () {
it('should list all remotes', async function() { it('should list all remotes', async function () {
await git.git('remote', 'set-url', 'origin', 'https://test.org/test'); await git.git('remote', 'set-url', 'origin', 'https://test.org/test');
await git.git('remote', 'add', 'second-remote', 'https://test.org/test2'); await git.git('remote', 'add', 'second-remote', 'https://test.org/test2');
@@ -48,13 +48,13 @@ describe('utils/git', function() {
'origin\thttps://test.org/test (fetch)', 'origin\thttps://test.org/test (fetch)',
'origin\thttps://test.org/test (push)', 'origin\thttps://test.org/test (push)',
'second-remote\thttps://test.org/test2 (fetch)', 'second-remote\thttps://test.org/test2 (fetch)',
'second-remote\thttps://test.org/test2 (push)' 'second-remote\thttps://test.org/test2 (push)',
]); ]);
}); });
}); });
describe('the "branches"-function', function() { describe('the "branches"-function', function () {
it('should list all branches', async function() { it('should list all branches', async function () {
await git.git('branch', 'test'); await git.git('branch', 'test');
await git.git('branch', 'test2'); await git.git('branch', 'test2');
@@ -64,32 +64,32 @@ describe('utils/git', function() {
' test', ' test',
' test2', ' test2',
' remotes/origin/HEAD -> origin/master', ' remotes/origin/HEAD -> origin/master',
' remotes/origin/master' ' remotes/origin/master',
]); ]);
}); });
}); });
describe('the "commitInfo"-function', function() { describe('the "commitInfo"-function', function () {
it('should list head and master sha', async function() { it('should list head and master sha', async function () {
const result = await git.commitInfo(); const result = await git.commitInfo();
expect(result.masterSha).to.equal(result.headSha); expect(result.masterSha).to.equal(result.headSha);
expect(result.masterSha).to.match(/^[0-9a-f]+$/); expect(result.masterSha).to.match(/^[0-9a-f]+$/);
expect(result.headSha).to.match(/^[0-9a-f]+$/); expect(result.headSha).to.match(/^[0-9a-f]+$/);
}); });
it('should have "isMaster=true" if the master branch is checked out', async function() { it('should have "isMaster=true" if the master branch is checked out', async function () {
const result = await git.commitInfo(); const result = await git.commitInfo();
expect(result.isMaster).to.be.true(); expect(result.isMaster).to.be.true();
}); });
it('should have "isMaster=true" if the current commit is the last commit of the master branch', async function() { it('should have "isMaster=true" if the current commit is the last commit of the master branch', async function () {
await git.git('checkout', '-b', 'new-branch'); await git.git('checkout', '-b', 'new-branch');
const result = await git.commitInfo(); const result = await git.commitInfo();
expect(result.isMaster).to.be.true(); expect(result.isMaster).to.be.true();
}); });
it('should have "isMaster=false" if the current commit is NOT the last commit of the master branch', async function() { it('should have "isMaster=false" if the current commit is NOT the last commit of the master branch', async function () {
await git.git('checkout', '-b', 'new-branch'); await git.git('checkout', '-b', 'new-branch');
fs.writeFile('new-file.txt', 'new-file'); fs.writeFile('new-file.txt', 'new-file');
await git.add('new-file.txt'); await git.add('new-file.txt');
@@ -99,13 +99,13 @@ describe('utils/git', function() {
expect(result.isMaster).to.be.false(); expect(result.isMaster).to.be.false();
}); });
it('should show the current tag', async function() { it('should show the current tag', async function () {
await git.git('tag', 'test-tag'); await git.git('tag', 'test-tag');
const result = await git.commitInfo(); const result = await git.commitInfo();
expect(result.tagName).to.be.equal('test-tag'); expect(result.tagName).to.be.equal('test-tag');
}); });
it('should show a version tag rather than standard tags', async function() { it('should show a version tag rather than standard tags', async function () {
await git.git('tag', 'test-tag'); await git.git('tag', 'test-tag');
await git.git('tag', 'v1.2'); await git.git('tag', 'v1.2');
await git.git('tag', 'test-tag2'); await git.git('tag', 'test-tag2');
@@ -113,7 +113,7 @@ describe('utils/git', function() {
expect(result.tagName).to.be.equal('v1.2'); expect(result.tagName).to.be.equal('v1.2');
}); });
it('should show no tag if there is no tag', async function() { it('should show no tag if there is no tag', async function () {
const result = await git.commitInfo(); const result = await git.commitInfo();
expect(result.tagName).to.be.null(); expect(result.tagName).to.be.null();
}); });
+2 -2
View File
@@ -2,9 +2,9 @@ module.exports = { createRegisterAsyncTaskFn };
function createRegisterAsyncTaskFn(grunt) { function createRegisterAsyncTaskFn(grunt) {
return function registerAsyncTask(name, asyncFunction) { return function registerAsyncTask(name, asyncFunction) {
grunt.registerTask(name, function() { grunt.registerTask(name, function () {
asyncFunction() asyncFunction()
.catch(error => { .catch((error) => {
grunt.fatal(error); grunt.fatal(error);
}) })
.finally(this.async()); .finally(this.async());
+2 -2
View File
@@ -1,13 +1,13 @@
const childProcess = require('child_process'); const childProcess = require('child_process');
module.exports = { module.exports = {
execNodeJsScriptWithInheritedOutput execNodeJsScriptWithInheritedOutput,
}; };
async function execNodeJsScriptWithInheritedOutput(command, args) { async function execNodeJsScriptWithInheritedOutput(command, args) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const child = childProcess.fork(command, args, { stdio: 'inherit' }); const child = childProcess.fork(command, args, { stdio: 'inherit' });
child.on('close', code => { child.on('close', (code) => {
if (code !== 0) { if (code !== 0) {
reject(new Error(`Child process failed with exit-code ${code}`)); reject(new Error(`Child process failed with exit-code ${code}`));
} }
+3 -3
View File
@@ -14,7 +14,7 @@ module.exports = {
headSha, headSha,
masterSha, masterSha,
tagName: await getTagName(), tagName: await getTagName(),
isMaster: headSha === masterSha isMaster: headSha === masterSha,
}; };
}, },
async add(path) { async add(path) {
@@ -23,7 +23,7 @@ module.exports = {
async commit(message) { async commit(message) {
return git('commit', '--message', message); return git('commit', '--message', message);
}, },
git // visible for testing git, // visible for testing
}; };
async function getHeadSha() { async function getHeadSha() {
@@ -52,7 +52,7 @@ async function getTagName() {
} }
const tags = trimmedStdout.split(/\n|\r\n/); const tags = trimmedStdout.split(/\n|\r\n/);
const versionTags = tags.filter(tag => /^v/.test(tag)); const versionTags = tags.filter((tag) => /^v/.test(tag));
if (versionTags[0] != null) { if (versionTags[0] != null) {
return versionTags[0]; return versionTags[0];
} }
+7 -7
View File
@@ -2,7 +2,7 @@ const git = require('./util/git');
const semver = require('semver'); const semver = require('semver');
const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task'); const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task');
module.exports = function(grunt) { module.exports = function (grunt) {
const registerAsyncTask = createRegisterAsyncTaskFn(grunt); const registerAsyncTask = createRegisterAsyncTaskFn(grunt);
registerAsyncTask('version', async () => { registerAsyncTask('version', async () => {
@@ -22,27 +22,27 @@ module.exports = function(grunt) {
{ {
path: 'lib/handlebars/base.js', path: 'lib/handlebars/base.js',
regex: /const VERSION = ['"](.*)['"];/, regex: /const VERSION = ['"](.*)['"];/,
replacement: `const VERSION = '${version}';` replacement: `const VERSION = '${version}';`,
}, },
{ {
path: 'components/bower.json', path: 'components/bower.json',
regex: /"version":.*/, regex: /"version":.*/,
replacement: `"version": "${version}",` replacement: `"version": "${version}",`,
}, },
{ {
path: 'components/package.json', path: 'components/package.json',
regex: /"version":.*/, regex: /"version":.*/,
replacement: `"version": "${version}",` replacement: `"version": "${version}",`,
}, },
{ {
path: 'components/handlebars.js.nuspec', path: 'components/handlebars.js.nuspec',
regex: /<version>.*<\/version>/, regex: /<version>.*<\/version>/,
replacement: `<version>${version}</version>` replacement: `<version>${version}</version>`,
} },
]; ];
await Promise.all( await Promise.all(
replaceSpec.map(replaceSpec => replaceSpec.map((replaceSpec) =>
replaceAndAdd( replaceAndAdd(
replaceSpec.path, replaceSpec.path,
replaceSpec.regex, replaceSpec.regex,
+2 -2
View File
@@ -1,6 +1,6 @@
module.exports = { module.exports = {
rules: { rules: {
'no-console': 'off', 'no-console': 'off',
'no-var': 'off' 'no-var': 'off',
} },
}; };
+4 -4
View File
@@ -2,13 +2,13 @@ var async = require('neo-async'),
fs = require('fs'), fs = require('fs'),
zlib = require('zlib'); zlib = require('zlib');
module.exports = function(grunt, callback) { module.exports = function (grunt, callback) {
var distFiles = fs.readdirSync('dist'), var distFiles = fs.readdirSync('dist'),
distSizes = {}; distSizes = {};
async.each( async.each(
distFiles, distFiles,
function(file, callback) { function (file, callback) {
var content; var content;
try { try {
content = fs.readFileSync('dist/' + file); content = fs.readFileSync('dist/' + file);
@@ -24,7 +24,7 @@ module.exports = function(grunt, callback) {
file = file.replace(/\.js/, '').replace(/\./g, '_'); file = file.replace(/\.js/, '').replace(/\./g, '_');
distSizes[file] = content.length; distSizes[file] = content.length;
zlib.gzip(content, function(err, data) { zlib.gzip(content, function (err, data) {
if (err) { if (err) {
throw err; throw err;
} }
@@ -33,7 +33,7 @@ module.exports = function(grunt, callback) {
callback(); callback();
}); });
}, },
function() { function () {
grunt.log.writeln( grunt.log.writeln(
'Distribution sizes: ' + JSON.stringify(distSizes, undefined, 2) 'Distribution sizes: ' + JSON.stringify(distSizes, undefined, 2)
); );
+1 -1
View File
@@ -1,7 +1,7 @@
var fs = require('fs'); var fs = require('fs');
var metrics = fs.readdirSync(__dirname); var metrics = fs.readdirSync(__dirname);
metrics.forEach(function(metric) { metrics.forEach(function (metric) {
if (metric === 'index.js' || !/(.*)\.js$/.test(metric)) { if (metric === 'index.js' || !/(.*)\.js$/.test(metric)) {
return; return;
} }
+3 -3
View File
@@ -1,17 +1,17 @@
var _ = require('underscore'), var _ = require('underscore'),
templates = require('./templates'); templates = require('./templates');
module.exports = function(grunt, callback) { module.exports = function (grunt, callback) {
// Deferring to here in case we have a build for parser, etc as part of this grunt exec // Deferring to here in case we have a build for parser, etc as part of this grunt exec
var Handlebars = require('../../lib'); var Handlebars = require('../../lib');
var templateSizes = {}; var templateSizes = {};
_.each(templates, function(info, template) { _.each(templates, function (info, template) {
var src = info.handlebars, var src = info.handlebars,
compiled = Handlebars.precompile(src, {}), compiled = Handlebars.precompile(src, {}),
knownHelpers = Handlebars.precompile(src, { knownHelpers = Handlebars.precompile(src, {
knownHelpersOnly: true, knownHelpersOnly: true,
knownHelpers: info.helpers knownHelpers: info.helpers,
}); });
templateSizes[template] = compiled.length; templateSizes[template] = compiled.length;
+4 -4
View File
@@ -1,13 +1,13 @@
module.exports = { module.exports = {
helpers: { helpers: {
foo: function() { foo: function () {
return ''; return '';
} },
}, },
context: { context: {
bar: true bar: true,
}, },
handlebars: handlebars:
'{{foo person "person" 1 true foo=bar foo="person" foo=1 foo=true}}' '{{foo person "person" 1 true foo=bar foo="person" foo=1 foo=true}}',
}; };
+3 -3
View File
@@ -4,10 +4,10 @@ module.exports = {
{ name: 'Moe' }, { name: 'Moe' },
{ name: 'Larry' }, { name: 'Larry' },
{ name: 'Curly' }, { name: 'Curly' },
{ name: 'Shemp' } { name: 'Shemp' },
] ],
}, },
handlebars: '{{#each names}}{{name}}{{/each}}', handlebars: '{{#each names}}{{name}}{{/each}}',
dust: '{#names}{name}{/names}', dust: '{#names}{name}{/names}',
mustache: '{{#names}}{{name}}{{/names}}' mustache: '{{#names}}{{name}}{{/names}}',
}; };
+3 -3
View File
@@ -4,8 +4,8 @@ module.exports = {
{ name: 'Moe' }, { name: 'Moe' },
{ name: 'Larry' }, { name: 'Larry' },
{ name: 'Curly' }, { name: 'Curly' },
{ name: 'Shemp' } { name: 'Shemp' },
] ],
}, },
handlebars: '{{#names}}{{name}}{{/names}}' handlebars: '{{#names}}{{name}}{{/names}}',
}; };
+4 -4
View File
@@ -2,18 +2,18 @@ var fs = require('fs');
module.exports = { module.exports = {
context: { context: {
header: function() { header: function () {
return 'Colors'; return 'Colors';
}, },
hasItems: true, // To make things fairer in mustache land due to no `{{if}}` construct on arrays hasItems: true, // To make things fairer in mustache land due to no `{{if}}` construct on arrays
items: [ items: [
{ name: 'red', current: true, url: '#Red' }, { name: 'red', current: true, url: '#Red' },
{ name: 'green', current: false, url: '#Green' }, { name: 'green', current: false, url: '#Green' },
{ name: 'blue', current: false, url: '#Blue' } { name: 'blue', current: false, url: '#Blue' },
] ],
}, },
handlebars: fs.readFileSync(__dirname + '/complex.handlebars').toString(), handlebars: fs.readFileSync(__dirname + '/complex.handlebars').toString(),
dust: fs.readFileSync(__dirname + '/complex.dust').toString(), dust: fs.readFileSync(__dirname + '/complex.dust').toString(),
mustache: fs.readFileSync(__dirname + '/complex.mustache').toString() mustache: fs.readFileSync(__dirname + '/complex.mustache').toString(),
}; };
+3 -3
View File
@@ -4,8 +4,8 @@ module.exports = {
{ name: 'Moe' }, { name: 'Moe' },
{ name: 'Larry' }, { name: 'Larry' },
{ name: 'Curly' }, { name: 'Curly' },
{ name: 'Shemp' } { name: 'Shemp' },
] ],
}, },
handlebars: '{{#each names}}{{@index}}{{name}}{{/each}}' handlebars: '{{#each names}}{{@index}}{{name}}{{/each}}',
}; };
+3 -3
View File
@@ -4,10 +4,10 @@ module.exports = {
{ name: 'Moe' }, { name: 'Moe' },
{ name: 'Larry' }, { name: 'Larry' },
{ name: 'Curly' }, { name: 'Curly' },
{ name: 'Shemp' } { name: 'Shemp' },
], ],
foo: 'bar' foo: 'bar',
}, },
handlebars: '{{#each names}}{{../foo}}{{/each}}', handlebars: '{{#each names}}{{../foo}}{{/each}}',
mustache: '{{#names}}{{foo}}{{/names}}' mustache: '{{#names}}{{foo}}{{/names}}',
}; };
+3 -3
View File
@@ -4,11 +4,11 @@ module.exports = {
{ bat: 'foo', name: ['Moe'] }, { bat: 'foo', name: ['Moe'] },
{ bat: 'foo', name: ['Larry'] }, { bat: 'foo', name: ['Larry'] },
{ bat: 'foo', name: ['Curly'] }, { bat: 'foo', name: ['Curly'] },
{ bat: 'foo', name: ['Shemp'] } { bat: 'foo', name: ['Shemp'] },
], ],
foo: 'bar' foo: 'bar',
}, },
handlebars: handlebars:
'{{#each names}}{{#each name}}{{../bat}}{{../../foo}}{{/each}}{{/each}}', '{{#each names}}{{#each name}}{{../bat}}{{../../foo}}{{/each}}{{/each}}',
mustache: '{{#names}}{{#name}}{{bat}}{{foo}}{{/name}}{{/names}}' mustache: '{{#names}}{{#name}}{{bat}}{{foo}}{{/name}}{{/names}}',
}; };
+1 -1
View File
@@ -1,7 +1,7 @@
var fs = require('fs'); var fs = require('fs');
var templates = fs.readdirSync(__dirname); var templates = fs.readdirSync(__dirname);
templates.forEach(function(template) { templates.forEach(function (template) {
if (template === 'index.js' || !/(.*)\.js$/.test(template)) { if (template === 'index.js' || !/(.*)\.js$/.test(template)) {
return; return;
} }
+1 -1
View File
@@ -1,4 +1,4 @@
module.exports = { module.exports = {
context: { person: { name: 'Larry', age: 45 } }, context: { person: { name: 'Larry', age: 45 } },
handlebars: '{{#person}}{{name}}{{age}}{{/person}}' handlebars: '{{#person}}{{name}}{{age}}{{/person}}',
}; };
+1 -1
View File
@@ -2,5 +2,5 @@ module.exports = {
context: { person: { name: 'Larry', age: 45 } }, context: { person: { name: 'Larry', age: 45 } },
handlebars: '{{#with person}}{{name}}{{age}}{{/with}}', handlebars: '{{#with person}}{{name}}{{age}}{{/with}}',
dust: '{#person}{name}{age}{/person}', dust: '{#person}{name}{age}{/person}',
mustache: '{{#person}}{{name}}{{age}}{{/person}}' mustache: '{{#person}}{{name}}{{age}}{{/person}}',
}; };
+3 -3
View File
@@ -1,13 +1,13 @@
module.exports = { module.exports = {
context: { context: {
name: '1', name: '1',
kids: [{ name: '1.1', kids: [{ name: '1.1.1', kids: [] }] }] kids: [{ name: '1.1', kids: [{ name: '1.1.1', kids: [] }] }],
}, },
partials: { partials: {
mustache: { recursion: '{{name}}{{#kids}}{{>recursion}}{{/kids}}' }, mustache: { recursion: '{{name}}{{#kids}}{{>recursion}}{{/kids}}' },
handlebars: { recursion: '{{name}}{{#each kids}}{{>recursion}}{{/each}}' } handlebars: { recursion: '{{name}}{{#each kids}}{{>recursion}}{{/each}}' },
}, },
handlebars: '{{name}}{{#each kids}}{{>recursion}}{{/each}}', handlebars: '{{name}}{{#each kids}}{{>recursion}}{{/each}}',
dust: '{name}{#kids}{>recursion:./}{/kids}', dust: '{name}{#kids}{>recursion:./}{/kids}',
mustache: '{{name}}{{#kids}}{{>recursion}}{{/kids}}' mustache: '{{name}}{{#kids}}{{>recursion}}{{/kids}}',
}; };
+5 -5
View File
@@ -3,17 +3,17 @@ module.exports = {
peeps: [ peeps: [
{ name: 'Moe', count: 15 }, { name: 'Moe', count: 15 },
{ name: 'Larry', count: 5 }, { name: 'Larry', count: 5 },
{ name: 'Curly', count: 1 } { name: 'Curly', count: 1 },
] ],
}, },
partials: { partials: {
mustache: { variables: 'Hello {{name}}! You have {{count}} new messages.' }, mustache: { variables: 'Hello {{name}}! You have {{count}} new messages.' },
handlebars: { handlebars: {
variables: 'Hello {{name}}! You have {{count}} new messages.' variables: 'Hello {{name}}! You have {{count}} new messages.',
} },
}, },
handlebars: '{{#each peeps}}{{>variables}}{{/each}}', handlebars: '{{#each peeps}}{{>variables}}{{/each}}',
dust: '{#peeps}{>variables/}{/peeps}', dust: '{#peeps}{>variables/}{/peeps}',
mustache: '{{#peeps}}{{>variables}}{{/peeps}}' mustache: '{{#peeps}}{{>variables}}{{/peeps}}',
}; };
+1 -1
View File
@@ -3,5 +3,5 @@ module.exports = {
handlebars: handlebars:
'{{person.name.bar.baz}}{{person.age}}{{person.foo}}{{animal.age}}', '{{person.name.bar.baz}}{{person.age}}{{person.foo}}{{animal.age}}',
dust: '{person.name.bar.baz}{person.age}{person.foo}{animal.age}', dust: '{person.name.bar.baz}{person.age}{person.foo}{animal.age}',
mustache: '{{person.name.bar.baz}}{{person.age}}{{person.foo}}{{animal.age}}' mustache: '{{person.name.bar.baz}}{{person.age}}{{person.foo}}{{animal.age}}',
}; };
+1 -1
View File
@@ -2,5 +2,5 @@ module.exports = {
context: {}, context: {},
handlebars: 'Hello world', handlebars: 'Hello world',
dust: 'Hello world', dust: 'Hello world',
mustache: 'Hello world' mustache: 'Hello world',
}; };
+4 -4
View File
@@ -1,13 +1,13 @@
module.exports = { module.exports = {
helpers: { helpers: {
echo: function(value) { echo: function (value) {
return 'foo ' + value; return 'foo ' + value;
}, },
header: function() { header: function () {
return 'Colors'; return 'Colors';
} },
}, },
handlebars: '{{echo (header)}}' handlebars: '{{echo (header)}}',
}; };
module.exports.context = module.exports.helpers; module.exports.context = module.exports.helpers;
+1 -1
View File
@@ -2,5 +2,5 @@ module.exports = {
context: { name: 'Mick', count: 30 }, context: { name: 'Mick', count: 30 },
handlebars: 'Hello {{name}}! You have {{count}} new messages.', handlebars: 'Hello {{name}}! You have {{count}} new messages.',
dust: 'Hello {name}! You have {count} new messages.', dust: 'Hello {name}! You have {count} new messages.',
mustache: 'Hello {{name}}! You have {{count}} new messages.' mustache: 'Hello {{name}}! You have {{count}} new messages.',
}; };
+18 -18
View File
@@ -33,26 +33,26 @@ function makeSuite(bench, name, template, handlebarsOnly) {
var handlebar = Handlebars.compile(template.handlebars, { data: false }), var handlebar = Handlebars.compile(template.handlebars, { data: false }),
compat = Handlebars.compile(template.handlebars, { compat = Handlebars.compile(template.handlebars, {
data: false, data: false,
compat: true compat: true,
}), }),
options = { helpers: template.helpers }; options = { helpers: template.helpers };
_.each(template.partials && template.partials.handlebars, function( _.each(
partial, template.partials && template.partials.handlebars,
partialName function (partial, partialName) {
) { Handlebars.registerPartial(
Handlebars.registerPartial( partialName,
partialName, Handlebars.compile(partial, { data: false })
Handlebars.compile(partial, { data: false }) );
); }
}); );
handlebarsOut = handlebar(context, options); handlebarsOut = handlebar(context, options);
bench('handlebars', function() { bench('handlebars', function () {
handlebar(context, options); handlebar(context, options);
}); });
compatOut = compat(context, options); compatOut = compat(context, options);
bench('compat', function() { bench('compat', function () {
compat(context, options); compat(context, options);
}); });
@@ -65,12 +65,12 @@ function makeSuite(bench, name, template, handlebarsOnly) {
dustOut = false; dustOut = false;
dust.loadSource(dust.compile(template.dust, templateName)); dust.loadSource(dust.compile(template.dust, templateName));
dust.render(templateName, context, function(err, out) { dust.render(templateName, context, function (err, out) {
dustOut = out; dustOut = out;
}); });
bench('dust', function() { bench('dust', function () {
dust.render(templateName, context, function() {}); dust.render(templateName, context, function () {});
}); });
} else { } else {
bench('dust', error); bench('dust', error);
@@ -84,7 +84,7 @@ function makeSuite(bench, name, template, handlebarsOnly) {
if (mustacheSource) { if (mustacheSource) {
mustacheOut = Mustache.to_html(mustacheSource, context, mustachePartials); mustacheOut = Mustache.to_html(mustacheSource, context, mustachePartials);
bench('mustache', function() { bench('mustache', function () {
Mustache.to_html(mustacheSource, context, mustachePartials); Mustache.to_html(mustacheSource, context, mustachePartials);
}); });
} else { } else {
@@ -120,12 +120,12 @@ function makeSuite(bench, name, template, handlebarsOnly) {
compare(mustacheOut, 'mustache'); compare(mustacheOut, 'mustache');
} }
module.exports = function(grunt, callback) { module.exports = function (grunt, callback) {
// Deferring load in case we are being run inline with the grunt build // Deferring load in case we are being run inline with the grunt build
Handlebars = require('../../lib'); Handlebars = require('../../lib');
console.log('Execution Throughput'); console.log('Execution Throughput');
runner(grunt, makeSuite, function(times, scaled) { runner(grunt, makeSuite, function (times, scaled) {
callback(scaled); callback(scaled);
}); });
}; };
+27 -26
View File
@@ -12,21 +12,21 @@ function BenchWarmer() {
} }
BenchWarmer.prototype = { BenchWarmer.prototype = {
winners: function(benches) { winners: function (benches) {
return Benchmark.filter(benches, 'fastest'); return Benchmark.filter(benches, 'fastest');
}, },
suite: function(suite, fn) { suite: function (suite, fn) {
this.suiteName = suite; this.suiteName = suite;
this.times[suite] = {}; this.times[suite] = {};
this.first = true; this.first = true;
var self = this; var self = this;
fn(function(name, benchFn) { fn(function (name, benchFn) {
self.push(name, benchFn); self.push(name, benchFn);
}); });
}, },
push: function(name, fn) { push: function (name, fn) {
if (this.names.indexOf(name) === -1) { if (this.names.indexOf(name) === -1) {
this.names.push(name); this.names.push(name);
} }
@@ -38,16 +38,16 @@ BenchWarmer.prototype = {
var bench = new Benchmark(fn, { var bench = new Benchmark(fn, {
name: this.suiteName + ': ' + name, name: this.suiteName + ': ' + name,
onComplete: function() { onComplete: function () {
if (first) { if (first) {
self.startLine(suiteName); self.startLine(suiteName);
} }
self.writeBench(bench); self.writeBench(bench);
self.currentBenches.push(bench); self.currentBenches.push(bench);
}, },
onError: function() { onError: function () {
self.errors[this.name] = this; self.errors[this.name] = this;
} },
}); });
bench.suiteName = this.suiteName; bench.suiteName = this.suiteName;
bench.benchName = name; bench.benchName = name;
@@ -55,24 +55,24 @@ BenchWarmer.prototype = {
this.benchmarks.push(bench); this.benchmarks.push(bench);
}, },
bench: function(callback) { bench: function (callback) {
var self = this; var self = this;
this.printHeader('ops/msec', true); this.printHeader('ops/msec', true);
Benchmark.invoke(this.benchmarks, { Benchmark.invoke(this.benchmarks, {
name: 'run', name: 'run',
onComplete: function() { onComplete: function () {
self.scaleTimes(); self.scaleTimes();
self.startLine(''); self.startLine('');
console.log('\n'); console.log('\n');
self.printHeader('scaled'); self.printHeader('scaled');
_.each(self.scaled, function(value, name) { _.each(self.scaled, function (value, name) {
self.startLine(name); self.startLine(name);
_.each(self.names, function(lang) { _.each(self.names, function (lang) {
self.writeValue(value[lang] || ''); self.writeValue(value[lang] || '');
}); });
}); });
@@ -93,7 +93,7 @@ BenchWarmer.prototype = {
if (errors) { if (errors) {
console.log('\n\nErrors:\n'); console.log('\n\nErrors:\n');
Object.keys(self.errors).forEach(function(prop) { Object.keys(self.errors).forEach(function (prop) {
if (self.errors[prop].error.message !== 'EWOT') { if (self.errors[prop].error.message !== 'EWOT') {
bench = self.errors[prop]; bench = self.errors[prop];
console.log('\n' + bench.name + ':\n'); console.log('\n' + bench.name + ':\n');
@@ -107,22 +107,22 @@ BenchWarmer.prototype = {
} }
callback(); callback();
} },
}); });
console.log('\n'); console.log('\n');
}, },
scaleTimes: function() { scaleTimes: function () {
var scaled = (this.scaled = {}); var scaled = (this.scaled = {});
_.each( _.each(
this.times, this.times,
function(times, name) { function (times, name) {
var output = (scaled[name] = {}); var output = (scaled[name] = {});
_.each( _.each(
times, times,
function(time, lang) { function (time, lang) {
output[lang] = ( output[lang] = (
((time - this.minimum) / (this.maximum - this.minimum)) * ((time - this.minimum) / (this.maximum - this.minimum)) *
100 100
@@ -135,7 +135,7 @@ BenchWarmer.prototype = {
); );
}, },
printHeader: function(title, winners) { printHeader: function (title, winners) {
var benchSize = 0, var benchSize = 0,
names = this.names, names = this.names,
i, i,
@@ -168,12 +168,13 @@ BenchWarmer.prototype = {
console.log('\n' + new Array(horSize + 1).join('-')); console.log('\n' + new Array(horSize + 1).join('-'));
}, },
startLine: function(name) { startLine: function (name) {
var winners = Benchmark.map(this.winners(this.currentBenches), function( var winners = Benchmark.map(
bench this.winners(this.currentBenches),
) { function (bench) {
return bench.name.split(': ')[1]; return bench.name.split(': ')[1];
}); }
);
this.currentBenches = []; this.currentBenches = [];
@@ -184,7 +185,7 @@ BenchWarmer.prototype = {
this.writeValue(name); this.writeValue(name);
} }
}, },
writeBench: function(bench) { writeBench: function (bench) {
var out; var out;
if (!bench.error) { if (!bench.error) {
@@ -211,11 +212,11 @@ BenchWarmer.prototype = {
this.writeValue(out); this.writeValue(out);
}, },
writeValue: function(out) { writeValue: function (out) {
var padding = this.benchSize - out.length + 1; var padding = this.benchSize - out.length + 1;
out = out + new Array(padding).join(' '); out = out + new Array(padding).join(' ');
console.log(out); console.log(out);
} },
}; };
module.exports = BenchWarmer; module.exports = BenchWarmer;
+4 -4
View File
@@ -2,7 +2,7 @@ var _ = require('underscore'),
BenchWarmer = require('./benchwarmer'), BenchWarmer = require('./benchwarmer'),
templates = require('../templates'); templates = require('../templates');
module.exports = function(grunt, makeSuite, callback) { module.exports = function (grunt, makeSuite, callback) {
var warmer = new BenchWarmer(); var warmer = new BenchWarmer();
var handlebarsOnly = grunt.option('handlebars-only'), var handlebarsOnly = grunt.option('handlebars-only'),
@@ -11,17 +11,17 @@ module.exports = function(grunt, makeSuite, callback) {
grep = new RegExp(grep); grep = new RegExp(grep);
} }
_.each(templates, function(template, name) { _.each(templates, function (template, name) {
if (!template.handlebars || (grep && !grep.test(name))) { if (!template.handlebars || (grep && !grep.test(name))) {
return; return;
} }
warmer.suite(name, function(bench) { warmer.suite(name, function (bench) {
makeSuite(bench, name, template, handlebarsOnly); makeSuite(bench, name, template, handlebarsOnly);
}); });
}); });
warmer.bench(function() { warmer.bench(function () {
if (callback) { if (callback) {
callback(warmer.times, warmer.scaled); callback(warmer.times, warmer.scaled);
} }
+2 -2
View File
@@ -1,5 +1,5 @@
module.exports = { module.exports = {
parserOptions: { parserOptions: {
ecmaVersion: 2018 ecmaVersion: 2018,
} },
}; };
+6 -6
View File
@@ -5,23 +5,23 @@ const config = {
projects: [ projects: [
{ {
name: 'chromium', name: 'chromium',
use: { ...devices['Desktop Chrome'] } use: { ...devices['Desktop Chrome'] },
}, },
{ {
name: 'firefox', name: 'firefox',
use: { ...devices['Desktop Firefox'] } use: { ...devices['Desktop Firefox'] },
}, },
{ {
name: 'webkit', name: 'webkit',
use: { ...devices['Desktop Safari'] } use: { ...devices['Desktop Safari'] },
} },
], ],
reporter: 'list', reporter: 'list',
webServer: { webServer: {
command: 'npm run test:serve', command: 'npm run test:serve',
port: 9999, port: 9999,
reuseExistingServer: false reuseExistingServer: false,
} },
}; };
module.exports = config; module.exports = config;
@@ -1,6 +1,6 @@
module.exports = { module.exports = {
rules: { rules: {
'no-console': 'off', 'no-console': 'off',
'no-var': 'off' 'no-var': 'off',
} },
}; };
@@ -4,7 +4,7 @@ export default {
input: 'src/index.js', input: 'src/index.js',
output: { output: {
file: 'dist/bundle.js', file: 'dist/bundle.js',
format: 'es' format: 'es',
}, },
plugins: [nodeResolve()] plugins: [nodeResolve()],
}; };
@@ -3,10 +3,10 @@ module.exports = {
root: true, root: true,
extends: ['eslint:recommended', 'prettier'], extends: ['eslint:recommended', 'prettier'],
env: { env: {
browser: true browser: true,
}, },
parserOptions: { parserOptions: {
sourceType: 'module', sourceType: 'module',
ecmaVersion: 6 ecmaVersion: 6,
} },
}; };
@@ -2,7 +2,7 @@ import * as Handlebars from 'handlebars/runtime';
import hbs from 'handlebars-inline-precompile'; import hbs from 'handlebars-inline-precompile';
import { assertEquals } from '../../webpack-test/src/lib/assert'; import { assertEquals } from '../../webpack-test/src/lib/assert';
Handlebars.registerHelper('loud', function(text) { Handlebars.registerHelper('loud', function (text) {
return text.toUpperCase(); return text.toUpperCase();
}); });
@@ -3,8 +3,8 @@ const fs = require('fs');
const testFiles = fs.readdirSync('src'); const testFiles = fs.readdirSync('src');
const entryPoints = {}; const entryPoints = {};
testFiles testFiles
.filter(file => file.match(/-test.js$/)) .filter((file) => file.match(/-test.js$/))
.forEach(file => { .forEach((file) => {
entryPoints[file] = `./src/${file}`; entryPoints[file] = `./src/${file}`;
}); });
@@ -13,7 +13,7 @@ module.exports = {
mode: 'production', mode: 'production',
output: { output: {
filename: '[name]', filename: '[name]',
path: __dirname + '/dist' path: __dirname + '/dist',
}, },
module: { module: {
rules: [ rules: [
@@ -22,12 +22,12 @@ module.exports = {
exclude: /node_modules/, exclude: /node_modules/,
use: { use: {
loader: 'babel-loader', loader: 'babel-loader',
options: { cacheDirectory: false } options: { cacheDirectory: false },
} },
} },
] ],
}, },
optimization: { optimization: {
minimize: false minimize: false,
} },
}; };
@@ -3,10 +3,10 @@ module.exports = {
extends: ['eslint:recommended', 'prettier'], extends: ['eslint:recommended', 'prettier'],
env: { env: {
node: true, node: true,
browser: true browser: true,
}, },
parserOptions: { parserOptions: {
sourceType: 'module', sourceType: 'module',
ecmaVersion: 6 ecmaVersion: 6,
} },
}; };

Some files were not shown because too many files have changed in this diff Show More