style: reformat all files using prettier
This commit is contained in:
+77
-27
@@ -1,22 +1,27 @@
|
|||||||
/* 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'),
|
||||||
|
|
||||||
clean: ['tmp', 'dist', 'lib/handlebars/compiler/parser.js', 'integration-testing/**/node_modules'],
|
clean: [
|
||||||
|
'tmp',
|
||||||
|
'dist',
|
||||||
|
'lib/handlebars/compiler/parser.js',
|
||||||
|
'integration-testing/**/node_modules'
|
||||||
|
],
|
||||||
|
|
||||||
copy: {
|
copy: {
|
||||||
dist: {
|
dist: {
|
||||||
options: {
|
options: {
|
||||||
processContent: function(content) {
|
processContent: function(content) {
|
||||||
return grunt.template.process('/**!\n\n @license\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n*/\n')
|
return (
|
||||||
+ content;
|
grunt.template.process(
|
||||||
|
'/**!\n\n @license\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n*/\n'
|
||||||
|
) + content
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
files: [
|
files: [{ expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/' }]
|
||||||
{expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/'}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
cdnjs: {
|
cdnjs: {
|
||||||
files: [
|
files: [
|
||||||
@@ -25,7 +30,12 @@ module.exports = function(grunt) {
|
|||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
files: [
|
files: [
|
||||||
{expand: true, cwd: 'components/', src: ['**'], dest: 'dist/components'},
|
{
|
||||||
|
expand: true,
|
||||||
|
cwd: 'components/',
|
||||||
|
src: ['**'],
|
||||||
|
dest: 'dist/components'
|
||||||
|
},
|
||||||
{ expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/components' }
|
{ expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/components' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -41,24 +51,28 @@ module.exports = function(grunt) {
|
|||||||
options: {
|
options: {
|
||||||
modules: 'amd'
|
modules: 'amd'
|
||||||
},
|
},
|
||||||
files: [{
|
files: [
|
||||||
|
{
|
||||||
expand: true,
|
expand: true,
|
||||||
cwd: 'lib/',
|
cwd: 'lib/',
|
||||||
src: '**/!(index).js',
|
src: '**/!(index).js',
|
||||||
dest: 'dist/amd/'
|
dest: 'dist/amd/'
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
cjs: {
|
cjs: {
|
||||||
options: {
|
options: {
|
||||||
modules: 'common'
|
modules: 'common'
|
||||||
},
|
},
|
||||||
files: [{
|
files: [
|
||||||
|
{
|
||||||
cwd: 'lib/',
|
cwd: 'lib/',
|
||||||
expand: true,
|
expand: true,
|
||||||
src: '**/!(index).js',
|
src: '**/!(index).js',
|
||||||
dest: 'dist/cjs/'
|
dest: 'dist/cjs/'
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
webpack: {
|
webpack: {
|
||||||
@@ -67,7 +81,12 @@ module.exports = function(grunt) {
|
|||||||
module: {
|
module: {
|
||||||
loaders: [
|
loaders: [
|
||||||
// the optional 'runtime' transformer tells babel to require the runtime instead of inlining it.
|
// the optional 'runtime' transformer tells babel to require the runtime instead of inlining it.
|
||||||
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?optional=runtime&loose=es6.modules&auxiliaryCommentBefore=istanbul%20ignore%20next' }
|
{
|
||||||
|
test: /\.jsx?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader:
|
||||||
|
'babel-loader?optional=runtime&loose=es6.modules&auxiliaryCommentBefore=istanbul%20ignore%20next'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
@@ -116,7 +135,8 @@ module.exports = function(grunt) {
|
|||||||
preserveComments: /(?:^!|@(?:license|preserve|cc_on))/
|
preserveComments: /(?:^!|@(?:license|preserve|cc_on))/
|
||||||
},
|
},
|
||||||
dist: {
|
dist: {
|
||||||
files: [{
|
files: [
|
||||||
|
{
|
||||||
cwd: 'dist/',
|
cwd: 'dist/',
|
||||||
expand: true,
|
expand: true,
|
||||||
src: ['handlebars*.js', '!*.min.js'],
|
src: ['handlebars*.js', '!*.min.js'],
|
||||||
@@ -124,7 +144,8 @@ module.exports = function(grunt) {
|
|||||||
rename: function(dest, src) {
|
rename: function(dest, src) {
|
||||||
return dest + src.replace(/\.js$/, '.min.js');
|
return dest + src.replace(/\.js$/, '.min.js');
|
||||||
}
|
}
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -148,7 +169,10 @@ module.exports = function(grunt) {
|
|||||||
all: {
|
all: {
|
||||||
options: {
|
options: {
|
||||||
build: process.env.TRAVIS_JOB_ID,
|
build: process.env.TRAVIS_JOB_ID,
|
||||||
urls: ['http://localhost:9999/spec/?headless=true', 'http://localhost:9999/spec/amd.html?headless=true'],
|
urls: [
|
||||||
|
'http://localhost:9999/spec/?headless=true',
|
||||||
|
'http://localhost:9999/spec/amd.html?headless=true'
|
||||||
|
],
|
||||||
detailedError: true,
|
detailedError: true,
|
||||||
concurrency: 4,
|
concurrency: 4,
|
||||||
browsers: [
|
browsers: [
|
||||||
@@ -156,20 +180,30 @@ module.exports = function(grunt) {
|
|||||||
{ browserName: 'firefox', platform: 'Linux' },
|
{ browserName: 'firefox', platform: 'Linux' },
|
||||||
// {browserName: 'safari', version: 9, platform: 'OS X 10.11'},
|
// {browserName: 'safari', version: 9, platform: 'OS X 10.11'},
|
||||||
// {browserName: 'safari', version: 8, platform: 'OS X 10.10'},
|
// {browserName: 'safari', version: 8, platform: 'OS X 10.10'},
|
||||||
{browserName: 'internet explorer', version: 11, platform: 'Windows 8.1'},
|
{
|
||||||
{browserName: 'internet explorer', version: 10, platform: 'Windows 8'}
|
browserName: 'internet explorer',
|
||||||
|
version: 11,
|
||||||
|
platform: 'Windows 8.1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
browserName: 'internet explorer',
|
||||||
|
version: 10,
|
||||||
|
platform: 'Windows 8'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sanity: {
|
sanity: {
|
||||||
options: {
|
options: {
|
||||||
build: process.env.TRAVIS_JOB_ID,
|
build: process.env.TRAVIS_JOB_ID,
|
||||||
urls: ['http://localhost:9999/spec/umd.html?headless=true', 'http://localhost:9999/spec/amd-runtime.html?headless=true', 'http://localhost:9999/spec/umd-runtime.html?headless=true'],
|
urls: [
|
||||||
|
'http://localhost:9999/spec/umd.html?headless=true',
|
||||||
|
'http://localhost:9999/spec/amd-runtime.html?headless=true',
|
||||||
|
'http://localhost:9999/spec/umd-runtime.html?headless=true'
|
||||||
|
],
|
||||||
detailedError: true,
|
detailedError: true,
|
||||||
concurrency: 2,
|
concurrency: 2,
|
||||||
browsers: [
|
browsers: [{ browserName: 'chrome' }]
|
||||||
{browserName: 'chrome'}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,7 +214,6 @@ module.exports = function(grunt) {
|
|||||||
bg: false,
|
bg: false,
|
||||||
fail: true
|
fail: true
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
@@ -231,13 +264,30 @@ module.exports = function(grunt) {
|
|||||||
this.registerTask('amd', ['babel:amd', 'requirejs']);
|
this.registerTask('amd', ['babel:amd', 'requirejs']);
|
||||||
|
|
||||||
grunt.registerTask('bench', ['metrics']);
|
grunt.registerTask('bench', ['metrics']);
|
||||||
grunt.registerTask('sauce', process.env.SAUCE_USERNAME ? ['tests', 'connect', 'saucelabs-mocha'] : []);
|
grunt.registerTask(
|
||||||
|
'sauce',
|
||||||
|
process.env.SAUCE_USERNAME ? ['tests', 'connect', 'saucelabs-mocha'] : []
|
||||||
|
);
|
||||||
// Requires secret properties (saucelabs-credentials etc.) from .travis.yaml
|
// Requires secret properties (saucelabs-credentials etc.) from .travis.yaml
|
||||||
grunt.registerTask('extensive-tests-and-publish-to-aws', ['default', 'bgShell:integrationTests', 'sauce', 'metrics', 'publish:latest']);
|
grunt.registerTask('extensive-tests-and-publish-to-aws', [
|
||||||
grunt.registerTask('on-file-change', ['build', 'amd', 'concat:tests', 'test']);
|
'default',
|
||||||
|
'bgShell:integrationTests',
|
||||||
|
'sauce',
|
||||||
|
'metrics',
|
||||||
|
'publish:latest'
|
||||||
|
]);
|
||||||
|
grunt.registerTask('on-file-change', [
|
||||||
|
'build',
|
||||||
|
'amd',
|
||||||
|
'concat:tests',
|
||||||
|
'test'
|
||||||
|
]);
|
||||||
|
|
||||||
// === Primary tasks ===
|
// === Primary tasks ===
|
||||||
grunt.registerTask('dev', ['clean', 'connect', 'watch']);
|
grunt.registerTask('dev', ['clean', 'connect', 'watch']);
|
||||||
grunt.registerTask('default', ['clean', 'build', 'test', 'release']);
|
grunt.registerTask('default', ['clean', 'build', 'test', 'release']);
|
||||||
grunt.registerTask('integration-tests', ['default', 'bgShell:integrationTests']);
|
grunt.registerTask('integration-tests', [
|
||||||
|
'default',
|
||||||
|
'bgShell:integrationTests'
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|||||||
+8
-3
@@ -6,7 +6,9 @@ module.exports = function(grunt, callback) {
|
|||||||
var distFiles = fs.readdirSync('dist'),
|
var distFiles = fs.readdirSync('dist'),
|
||||||
distSizes = {};
|
distSizes = {};
|
||||||
|
|
||||||
async.each(distFiles, function(file, callback) {
|
async.each(
|
||||||
|
distFiles,
|
||||||
|
function(file, callback) {
|
||||||
var content;
|
var content;
|
||||||
try {
|
try {
|
||||||
content = fs.readFileSync('dist/' + file);
|
content = fs.readFileSync('dist/' + file);
|
||||||
@@ -32,7 +34,10 @@ module.exports = function(grunt, callback) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
grunt.log.writeln('Distribution sizes: ' + JSON.stringify(distSizes, undefined, 2));
|
grunt.log.writeln(
|
||||||
|
'Distribution sizes: ' + JSON.stringify(distSizes, undefined, 2)
|
||||||
|
);
|
||||||
callback([distSizes]);
|
callback([distSizes]);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,16 @@ module.exports = function(grunt, callback) {
|
|||||||
_.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, {knownHelpersOnly: true, knownHelpers: info.helpers});
|
knownHelpers = Handlebars.precompile(src, {
|
||||||
|
knownHelpersOnly: true,
|
||||||
|
knownHelpers: info.helpers
|
||||||
|
});
|
||||||
|
|
||||||
templateSizes[template] = compiled.length;
|
templateSizes[template] = compiled.length;
|
||||||
templateSizes['knownOnly_' + template] = knownHelpers.length;
|
templateSizes['knownOnly_' + template] = knownHelpers.length;
|
||||||
});
|
});
|
||||||
grunt.log.writeln('Precompiled sizes: ' + JSON.stringify(templateSizes, undefined, 2));
|
grunt.log.writeln(
|
||||||
|
'Precompiled sizes: ' + JSON.stringify(templateSizes, undefined, 2)
|
||||||
|
);
|
||||||
callback([templateSizes]);
|
callback([templateSizes]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,5 +8,6 @@ module.exports = {
|
|||||||
bar: true
|
bar: true
|
||||||
},
|
},
|
||||||
|
|
||||||
handlebars: '{{foo person "person" 1 true foo=bar foo="person" foo=1 foo=true}}'
|
handlebars:
|
||||||
|
'{{foo person "person" 1 true foo=bar foo="person" foo=1 foo=true}}'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: { names: [{name: 'Moe'}, {name: 'Larry'}, {name: 'Curly'}, {name: 'Shemp'}] },
|
context: {
|
||||||
|
names: [
|
||||||
|
{ name: 'Moe' },
|
||||||
|
{ name: 'Larry' },
|
||||||
|
{ name: 'Curly' },
|
||||||
|
{ 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}}',
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: { names: [{name: 'Moe'}, {name: 'Larry'}, {name: 'Curly'}, {name: 'Shemp'}] },
|
context: {
|
||||||
|
names: [
|
||||||
|
{ name: 'Moe' },
|
||||||
|
{ name: 'Larry' },
|
||||||
|
{ name: 'Curly' },
|
||||||
|
{ name: 'Shemp' }
|
||||||
|
]
|
||||||
|
},
|
||||||
handlebars: '{{#names}}{{name}}{{/names}}'
|
handlebars: '{{#names}}{{name}}{{/names}}'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: { names: [{name: 'Moe'}, {name: 'Larry'}, {name: 'Curly'}, {name: 'Shemp'}] },
|
context: {
|
||||||
|
names: [
|
||||||
|
{ name: 'Moe' },
|
||||||
|
{ name: 'Larry' },
|
||||||
|
{ name: 'Curly' },
|
||||||
|
{ name: 'Shemp' }
|
||||||
|
]
|
||||||
|
},
|
||||||
handlebars: '{{#each names}}{{@index}}{{name}}{{/each}}'
|
handlebars: '{{#each names}}{{@index}}{{name}}{{/each}}'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: { names: [{name: 'Moe'}, {name: 'Larry'}, {name: 'Curly'}, {name: 'Shemp'}], foo: 'bar' },
|
context: {
|
||||||
|
names: [
|
||||||
|
{ name: 'Moe' },
|
||||||
|
{ name: 'Larry' },
|
||||||
|
{ name: 'Curly' },
|
||||||
|
{ name: 'Shemp' }
|
||||||
|
],
|
||||||
|
foo: 'bar'
|
||||||
|
},
|
||||||
handlebars: '{{#each names}}{{../foo}}{{/each}}',
|
handlebars: '{{#each names}}{{../foo}}{{/each}}',
|
||||||
mustache: '{{#names}}{{foo}}{{/names}}',
|
mustache: '{{#names}}{{foo}}{{/names}}',
|
||||||
eco: '<% for item in @names: %><%= @foo %><% end %>'
|
eco: '<% for item in @names: %><%= @foo %><% end %>'
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: { names: [{bat: 'foo', name: ['Moe']}, {bat: 'foo', name: ['Larry']}, {bat: 'foo', name: ['Curly']}, {bat: 'foo', name: ['Shemp']}], foo: 'bar' },
|
context: {
|
||||||
handlebars: '{{#each names}}{{#each name}}{{../bat}}{{../../foo}}{{/each}}{{/each}}',
|
names: [
|
||||||
|
{ bat: 'foo', name: ['Moe'] },
|
||||||
|
{ bat: 'foo', name: ['Larry'] },
|
||||||
|
{ bat: 'foo', name: ['Curly'] },
|
||||||
|
{ bat: 'foo', name: ['Shemp'] }
|
||||||
|
],
|
||||||
|
foo: 'bar'
|
||||||
|
},
|
||||||
|
handlebars:
|
||||||
|
'{{#each names}}{{#each name}}{{../bat}}{{../../foo}}{{/each}}{{/each}}',
|
||||||
mustache: '{{#names}}{{#name}}{{bat}}{{foo}}{{/name}}{{/names}}',
|
mustache: '{{#names}}{{#name}}{{bat}}{{foo}}{{/name}}{{/names}}',
|
||||||
eco: '<% for item in @names: %><% for child in item.name: %><%= item.bat %><%= @foo %><% end %><% end %>'
|
eco:
|
||||||
|
'<% for item in @names: %><% for child in item.name: %><%= item.bat %><%= @foo %><% end %><% end %>'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ 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;
|
||||||
}
|
}
|
||||||
module.exports[RegExp.$1] = require('./' + RegExp.$1);
|
module.exports[RegExp.$1] = require('./' + RegExp.$1);
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: { name: '1', kids: [{ name: '1.1', kids: [{name: '1.1.1', kids: []}] }] },
|
context: {
|
||||||
|
name: '1',
|
||||||
|
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}}' }
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: { peeps: [{name: 'Moe', count: 15}, {name: 'Larry', count: 5}, {name: 'Curly', count: 1}] },
|
context: {
|
||||||
|
peeps: [
|
||||||
|
{ name: 'Moe', count: 15 },
|
||||||
|
{ name: 'Larry', count: 5 },
|
||||||
|
{ 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: { variables: 'Hello {{name}}! You have {{count}} new messages.' }
|
handlebars: {
|
||||||
|
variables: 'Hello {{name}}! You have {{count}} new messages.'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handlebars: '{{#each peeps}}{{>variables}}{{/each}}',
|
handlebars: '{{#each peeps}}{{>variables}}{{/each}}',
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: { person: { name: { bar: { baz: 'Larry' } }, age: 45 } },
|
context: { person: { name: { bar: { baz: 'Larry' } }, age: 45 } },
|
||||||
handlebars: '{{person.name.bar.baz}}{{person.age}}{{person.foo}}{{animal.age}}',
|
handlebars:
|
||||||
|
'{{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}',
|
||||||
eco: '<%= @person.name.bar.baz %><%= @person.age %><%= @person.foo %><% if @animal: %><%= @animal.age %><% end %>',
|
eco:
|
||||||
|
'<%= @person.name.bar.baz %><%= @person.age %><%= @person.foo %><% if @animal: %><%= @animal.age %><% end %>',
|
||||||
mustache: '{{person.name.bar.baz}}{{person.age}}{{person.foo}}{{animal.age}}'
|
mustache: '{{person.name.bar.baz}}{{person.age}}{{person.foo}}{{animal.age}}'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,4 +5,3 @@ module.exports = {
|
|||||||
mustache: 'Hello {{name}}! You have {{count}} new messages.',
|
mustache: 'Hello {{name}}! You have {{count}} new messages.',
|
||||||
eco: 'Hello <%= @name %>! You have <%= @count %> new messages.'
|
eco: 'Hello <%= @name %>! You have <%= @count %> new messages.'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+38
-14
@@ -1,19 +1,27 @@
|
|||||||
var _ = require('underscore'),
|
var _ = require('underscore'),
|
||||||
runner = require('./util/template-runner'),
|
runner = require('./util/template-runner'),
|
||||||
|
eco,
|
||||||
eco, dust, Handlebars, Mustache;
|
dust,
|
||||||
|
Handlebars,
|
||||||
|
Mustache;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dust = require('dustjs-linkedin');
|
dust = require('dustjs-linkedin');
|
||||||
} catch (err) { /* NOP */ }
|
} catch (err) {
|
||||||
|
/* NOP */
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Mustache = require('mustache');
|
Mustache = require('mustache');
|
||||||
} catch (err) { /* NOP */ }
|
} catch (err) {
|
||||||
|
/* NOP */
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
eco = require('eco');
|
eco = require('eco');
|
||||||
} catch (err) { /* NOP */ }
|
} catch (err) {
|
||||||
|
/* NOP */
|
||||||
|
}
|
||||||
|
|
||||||
function error() {
|
function error() {
|
||||||
throw new Error('EWOT');
|
throw new Error('EWOT');
|
||||||
@@ -22,10 +30,8 @@ function error() {
|
|||||||
function makeSuite(bench, name, template, handlebarsOnly) {
|
function makeSuite(bench, name, template, handlebarsOnly) {
|
||||||
// Create aliases to minimize any impact from having to walk up the closure tree.
|
// Create aliases to minimize any impact from having to walk up the closure tree.
|
||||||
var templateName = name,
|
var templateName = name,
|
||||||
|
|
||||||
context = template.context,
|
context = template.context,
|
||||||
partials = template.partials,
|
partials = template.partials,
|
||||||
|
|
||||||
handlebarsOut,
|
handlebarsOut,
|
||||||
compatOut,
|
compatOut,
|
||||||
dustOut,
|
dustOut,
|
||||||
@@ -33,10 +39,19 @@ function makeSuite(bench, name, template, handlebarsOnly) {
|
|||||||
mustacheOut;
|
mustacheOut;
|
||||||
|
|
||||||
var handlebar = Handlebars.compile(template.handlebars, { data: false }),
|
var handlebar = Handlebars.compile(template.handlebars, { data: false }),
|
||||||
compat = Handlebars.compile(template.handlebars, {data: false, compat: true}),
|
compat = Handlebars.compile(template.handlebars, {
|
||||||
|
data: false,
|
||||||
|
compat: true
|
||||||
|
}),
|
||||||
options = { helpers: template.helpers };
|
options = { helpers: template.helpers };
|
||||||
_.each(template.partials && template.partials.handlebars, function(partial, partialName) {
|
_.each(template.partials && template.partials.handlebars, function(
|
||||||
Handlebars.registerPartial(partialName, Handlebars.compile(partial, {data: false}));
|
partial,
|
||||||
|
partialName
|
||||||
|
) {
|
||||||
|
Handlebars.registerPartial(
|
||||||
|
partialName,
|
||||||
|
Handlebars.compile(partial, { data: false })
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
handlebarsOut = handlebar(context, options);
|
handlebarsOut = handlebar(context, options);
|
||||||
@@ -58,7 +73,9 @@ 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) { dustOut = out; });
|
dust.render(templateName, context, function(err, out) {
|
||||||
|
dustOut = out;
|
||||||
|
});
|
||||||
|
|
||||||
bench('dust', function() {
|
bench('dust', function() {
|
||||||
dust.render(templateName, context, function() {});
|
dust.render(templateName, context, function() {});
|
||||||
@@ -107,9 +124,16 @@ function makeSuite(bench, name, template, handlebarsOnly) {
|
|||||||
b = b.replace(/\s/g, '');
|
b = b.replace(/\s/g, '');
|
||||||
|
|
||||||
if (handlebarsOut !== b) {
|
if (handlebarsOut !== b) {
|
||||||
throw new Error('Template output mismatch: ' + name
|
throw new Error(
|
||||||
+ '\n\nHandlebars: ' + handlebarsOut
|
'Template output mismatch: ' +
|
||||||
+ '\n\n' + lang + ': ' + b);
|
name +
|
||||||
|
'\n\nHandlebars: ' +
|
||||||
|
handlebarsOut +
|
||||||
|
'\n\n' +
|
||||||
|
lang +
|
||||||
|
': ' +
|
||||||
|
b
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+44
-17
@@ -33,16 +33,21 @@ BenchWarmer.prototype = {
|
|||||||
this.names.push(name);
|
this.names.push(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
var first = this.first, suiteName = this.suiteName, self = this;
|
var first = this.first,
|
||||||
|
suiteName = this.suiteName,
|
||||||
|
self = this;
|
||||||
this.first = false;
|
this.first = false;
|
||||||
|
|
||||||
var bench = new Benchmark(fn, {
|
var bench = new Benchmark(fn, {
|
||||||
name: this.suiteName + ': ' + name,
|
name: this.suiteName + ': ' + name,
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
if (first) { self.startLine(suiteName); }
|
if (first) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -75,10 +80,14 @@ BenchWarmer.prototype = {
|
|||||||
});
|
});
|
||||||
print('\n');
|
print('\n');
|
||||||
|
|
||||||
var errors = false, prop, bench;
|
var errors = false,
|
||||||
|
prop,
|
||||||
|
bench;
|
||||||
for (prop in self.errors) {
|
for (prop in self.errors) {
|
||||||
if (Object.prototype.hasOwnProperty.call(self, prop)
|
if (
|
||||||
&& self.errors[prop].error.message !== 'EWOT') {
|
Object.prototype.hasOwnProperty.call(self, prop) &&
|
||||||
|
self.errors[prop].error.message !== 'EWOT'
|
||||||
|
) {
|
||||||
errors = true;
|
errors = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -107,23 +116,39 @@ BenchWarmer.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
scaleTimes: function() {
|
scaleTimes: function() {
|
||||||
var scaled = this.scaled = {};
|
var scaled = (this.scaled = {});
|
||||||
_.each(this.times, function(times, name) {
|
_.each(
|
||||||
var output = scaled[name] = {};
|
this.times,
|
||||||
|
function(times, name) {
|
||||||
|
var output = (scaled[name] = {});
|
||||||
|
|
||||||
_.each(times, function(time, lang) {
|
_.each(
|
||||||
output[lang] = ((time - this.minimum) / (this.maximum - this.minimum) * 100).toFixed(2);
|
times,
|
||||||
}, this);
|
function(time, lang) {
|
||||||
}, this);
|
output[lang] = (
|
||||||
|
((time - this.minimum) / (this.maximum - this.minimum)) *
|
||||||
|
100
|
||||||
|
).toFixed(2);
|
||||||
|
},
|
||||||
|
this
|
||||||
|
);
|
||||||
|
},
|
||||||
|
this
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
printHeader: function(title, winners) {
|
printHeader: function(title, winners) {
|
||||||
var benchSize = 0, names = this.names, i, l;
|
var benchSize = 0,
|
||||||
|
names = this.names,
|
||||||
|
i,
|
||||||
|
l;
|
||||||
|
|
||||||
for (i = 0, l = names.length; i < l; i++) {
|
for (i = 0, l = names.length; i < l; i++) {
|
||||||
var name = names[i];
|
var name = names[i];
|
||||||
|
|
||||||
if (benchSize < name.length) { benchSize = name.length; }
|
if (benchSize < name.length) {
|
||||||
|
benchSize = name.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.nameSize = benchSize + 2;
|
this.nameSize = benchSize + 2;
|
||||||
@@ -146,7 +171,9 @@ BenchWarmer.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
startLine: function(name) {
|
startLine: function(name) {
|
||||||
var winners = Benchmark.map(this.winners(this.currentBenches), function(bench) {
|
var winners = Benchmark.map(this.winners(this.currentBenches), function(
|
||||||
|
bench
|
||||||
|
) {
|
||||||
return bench.name.split(': ')[1];
|
return bench.name.split(': ')[1];
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -164,7 +191,7 @@ BenchWarmer.prototype = {
|
|||||||
|
|
||||||
if (!bench.error) {
|
if (!bench.error) {
|
||||||
var count = bench.hz,
|
var count = bench.hz,
|
||||||
moe = count * bench.stats.rme / 100,
|
moe = (count * bench.stats.rme) / 100,
|
||||||
minimum,
|
minimum,
|
||||||
maximum;
|
maximum;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import * as Handlebars from 'handlebars/runtime'
|
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();
|
||||||
});
|
});
|
||||||
|
|
||||||
const template = hbs`{{loud name}}`;
|
const template = hbs`{{loud name}}`;
|
||||||
const output = template({name: 'yehuda'})
|
const output = template({ name: 'yehuda' });
|
||||||
|
|
||||||
assertEquals(output, 'YEHUDA')
|
assertEquals(output, 'YEHUDA');
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ module.exports = {
|
|||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
use: {
|
use: {
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
options: { cacheDirectory: false },
|
options: { cacheDirectory: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import Handlebars from 'handlebars';
|
import Handlebars from 'handlebars';
|
||||||
import { assertEquals } from './lib/assert';
|
import { assertEquals } from './lib/assert';
|
||||||
|
|
||||||
|
|
||||||
const template = Handlebars.compile('Author: {{author}}');
|
const template = Handlebars.compile('Author: {{author}}');
|
||||||
assertEquals(template({ author: 'Yehuda' }), 'Author: Yehuda');
|
assertEquals(template({ author: 'Yehuda' }), 'Author: Yehuda');
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import {assertEquals} from './lib/assert';
|
|||||||
import testTemplate from './test-template.handlebars';
|
import testTemplate from './test-template.handlebars';
|
||||||
assertEquals(testTemplate({ author: 'Yehuda' }).trim(), 'Author: Yehuda');
|
assertEquals(testTemplate({ author: 'Yehuda' }).trim(), 'Author: Yehuda');
|
||||||
|
|
||||||
|
|
||||||
const testTemplateRequire = require('./test-template.handlebars');
|
const testTemplateRequire = require('./test-template.handlebars');
|
||||||
assertEquals(testTemplateRequire({author: 'Yehuda'}).trim(), 'Author: Yehuda');
|
assertEquals(
|
||||||
|
testTemplateRequire({ author: 'Yehuda' }).trim(),
|
||||||
|
'Author: Yehuda'
|
||||||
|
);
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ module.exports = {
|
|||||||
path: __dirname + '/dist'
|
path: __dirname + '/dist'
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [{ test: /\.handlebars$/, loader: 'handlebars-loader' }]
|
||||||
{test: /\.handlebars$/, loader: 'handlebars-loader'}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+5
-1
@@ -2,7 +2,11 @@ import runtime from './handlebars.runtime';
|
|||||||
|
|
||||||
// Compiler imports
|
// Compiler imports
|
||||||
import AST from './handlebars/compiler/ast';
|
import AST from './handlebars/compiler/ast';
|
||||||
import { parser as Parser, parse, parseWithoutProcessing } from './handlebars/compiler/base';
|
import {
|
||||||
|
parser as Parser,
|
||||||
|
parse,
|
||||||
|
parseWithoutProcessing
|
||||||
|
} from './handlebars/compiler/base';
|
||||||
import { Compiler, compile, precompile } from './handlebars/compiler/compiler';
|
import { Compiler, compile, precompile } from './handlebars/compiler/compiler';
|
||||||
import JavaScriptCompiler from './handlebars/compiler/javascript-compiler';
|
import JavaScriptCompiler from './handlebars/compiler/javascript-compiler';
|
||||||
import Visitor from './handlebars/compiler/visitor';
|
import Visitor from './handlebars/compiler/visitor';
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ HandlebarsEnvironment.prototype = {
|
|||||||
|
|
||||||
registerHelper: function(name, fn) {
|
registerHelper: function(name, fn) {
|
||||||
if (toString.call(name) === objectType) {
|
if (toString.call(name) === objectType) {
|
||||||
if (fn) { throw new Exception('Arg not supported with multiple helpers'); }
|
if (fn) {
|
||||||
|
throw new Exception('Arg not supported with multiple helpers');
|
||||||
|
}
|
||||||
extend(this.helpers, name);
|
extend(this.helpers, name);
|
||||||
} else {
|
} else {
|
||||||
this.helpers[name] = fn;
|
this.helpers[name] = fn;
|
||||||
@@ -53,7 +55,9 @@ HandlebarsEnvironment.prototype = {
|
|||||||
extend(this.partials, name);
|
extend(this.partials, name);
|
||||||
} else {
|
} else {
|
||||||
if (typeof partial === 'undefined') {
|
if (typeof partial === 'undefined') {
|
||||||
throw new Exception(`Attempting to register a partial called "${name}" as undefined`);
|
throw new Exception(
|
||||||
|
`Attempting to register a partial called "${name}" as undefined`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
this.partials[name] = partial;
|
this.partials[name] = partial;
|
||||||
}
|
}
|
||||||
@@ -64,7 +68,9 @@ HandlebarsEnvironment.prototype = {
|
|||||||
|
|
||||||
registerDecorator: function(name, fn) {
|
registerDecorator: function(name, fn) {
|
||||||
if (toString.call(name) === objectType) {
|
if (toString.call(name) === objectType) {
|
||||||
if (fn) { throw new Exception('Arg not supported with multiple decorators'); }
|
if (fn) {
|
||||||
|
throw new Exception('Arg not supported with multiple decorators');
|
||||||
|
}
|
||||||
extend(this.decorators, name);
|
extend(this.decorators, name);
|
||||||
} else {
|
} else {
|
||||||
this.decorators[name] = fn;
|
this.decorators[name] = fn;
|
||||||
|
|||||||
@@ -5,24 +5,28 @@ let AST = {
|
|||||||
// * 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 (node.type === 'SubExpression')
|
return (
|
||||||
|| ((node.type === 'MustacheStatement' || node.type === 'BlockStatement')
|
node.type === 'SubExpression' ||
|
||||||
&& !!((node.params && node.params.length) || node.hash));
|
((node.type === 'MustacheStatement' ||
|
||||||
|
node.type === 'BlockStatement') &&
|
||||||
|
!!((node.params && node.params.length) || node.hash))
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
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 path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth;
|
return (
|
||||||
|
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
|
||||||
// must modify the object to operate properly.
|
// must modify the object to operate properly.
|
||||||
export default AST;
|
export default AST;
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ extend(yy, Helpers);
|
|||||||
|
|
||||||
export function parseWithoutProcessing(input, options) {
|
export function parseWithoutProcessing(input, options) {
|
||||||
// Just return if an already-compiled AST was passed in.
|
// Just return if an already-compiled AST was passed in.
|
||||||
if (input.type === 'Program') { return input; }
|
if (input.type === 'Program') {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
parser.yy = yy;
|
parser.yy = yy;
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ if (!SourceNode) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function castChunk(chunk, codeGen, loc) {
|
function castChunk(chunk, codeGen, loc) {
|
||||||
if (isArray(chunk)) {
|
if (isArray(chunk)) {
|
||||||
let ret = [];
|
let ret = [];
|
||||||
@@ -62,7 +61,6 @@ function castChunk(chunk, codeGen, loc) {
|
|||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function CodeGen(srcFile) {
|
function CodeGen(srcFile) {
|
||||||
this.srcFile = srcFile;
|
this.srcFile = srcFile;
|
||||||
this.source = [];
|
this.source = [];
|
||||||
@@ -104,7 +102,12 @@ CodeGen.prototype = {
|
|||||||
|
|
||||||
chunk = castChunk(chunk, this, loc);
|
chunk = castChunk(chunk, this, loc);
|
||||||
|
|
||||||
return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk);
|
return new SourceNode(
|
||||||
|
loc.start.line,
|
||||||
|
loc.start.column,
|
||||||
|
this.srcFile,
|
||||||
|
chunk
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
functionCall: function(fn, type, params) {
|
functionCall: function(fn, type, params) {
|
||||||
@@ -113,13 +116,17 @@ CodeGen.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
quotedString: function(str) {
|
quotedString: function(str) {
|
||||||
return '"' + (str + '')
|
return (
|
||||||
|
'"' +
|
||||||
|
(str + '')
|
||||||
.replace(/\\/g, '\\\\')
|
.replace(/\\/g, '\\\\')
|
||||||
.replace(/"/g, '\\"')
|
.replace(/"/g, '\\"')
|
||||||
.replace(/\n/g, '\\n')
|
.replace(/\n/g, '\\n')
|
||||||
.replace(/\r/g, '\\r')
|
.replace(/\r/g, '\\r')
|
||||||
.replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
|
.replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
|
||||||
.replace(/\u2029/g, '\\u2029') + '"';
|
.replace(/\u2029/g, '\\u2029') +
|
||||||
|
'"'
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
objectLiteral: function(obj) {
|
objectLiteral: function(obj) {
|
||||||
@@ -138,7 +145,6 @@ CodeGen.prototype = {
|
|||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
generateList: function(entries) {
|
generateList: function(entries) {
|
||||||
let ret = this.empty();
|
let ret = this.empty();
|
||||||
|
|
||||||
@@ -163,4 +169,3 @@ CodeGen.prototype = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default CodeGen;
|
export default CodeGen;
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ Compiler.prototype = {
|
|||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let opcode = this.opcodes[i],
|
let opcode = this.opcodes[i],
|
||||||
otherOpcode = other.opcodes[i];
|
otherOpcode = other.opcodes[i];
|
||||||
if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) {
|
if (
|
||||||
|
opcode.opcode !== otherOpcode.opcode ||
|
||||||
|
!argEquals(opcode.args, otherOpcode.args)
|
||||||
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,16 +57,20 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
options.blockParams = options.blockParams || [];
|
options.blockParams = options.blockParams || [];
|
||||||
|
|
||||||
options.knownHelpers = extend(Object.create(null), {
|
options.knownHelpers = extend(
|
||||||
'helperMissing': true,
|
Object.create(null),
|
||||||
'blockHelperMissing': true,
|
{
|
||||||
'each': true,
|
helperMissing: true,
|
||||||
'if': true,
|
blockHelperMissing: true,
|
||||||
'unless': true,
|
each: true,
|
||||||
'with': true,
|
if: true,
|
||||||
'log': true,
|
unless: true,
|
||||||
'lookup': true
|
with: true,
|
||||||
}, options.knownHelpers);
|
log: true,
|
||||||
|
lookup: true
|
||||||
|
},
|
||||||
|
options.knownHelpers
|
||||||
|
);
|
||||||
|
|
||||||
return this.accept(program);
|
return this.accept(program);
|
||||||
},
|
},
|
||||||
@@ -165,7 +172,10 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
let params = partial.params;
|
let params = partial.params;
|
||||||
if (params.length > 1) {
|
if (params.length > 1) {
|
||||||
throw new Exception('Unsupported number of partial arguments: ' + params.length, partial);
|
throw new Exception(
|
||||||
|
'Unsupported number of partial arguments: ' + params.length,
|
||||||
|
partial
|
||||||
|
);
|
||||||
} else if (!params.length) {
|
} else if (!params.length) {
|
||||||
if (this.options.explicitPartialContext) {
|
if (this.options.explicitPartialContext) {
|
||||||
this.opcode('pushLiteral', 'undefined');
|
this.opcode('pushLiteral', 'undefined');
|
||||||
@@ -208,7 +218,6 @@ 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);
|
||||||
@@ -260,13 +269,21 @@ Compiler.prototype = {
|
|||||||
if (this.options.knownHelpers[name]) {
|
if (this.options.knownHelpers[name]) {
|
||||||
this.opcode('invokeKnownHelper', params.length, name);
|
this.opcode('invokeKnownHelper', params.length, name);
|
||||||
} else if (this.options.knownHelpersOnly) {
|
} else if (this.options.knownHelpersOnly) {
|
||||||
throw new Exception('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr);
|
throw new Exception(
|
||||||
|
'You specified knownHelpersOnly, but used the unknown helper ' + name,
|
||||||
|
sexpr
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
path.strict = true;
|
path.strict = true;
|
||||||
path.falsy = true;
|
path.falsy = true;
|
||||||
|
|
||||||
this.accept(path);
|
this.accept(path);
|
||||||
this.opcode('invokeHelper', params.length, path.original, AST.helpers.simpleId(path));
|
this.opcode(
|
||||||
|
'invokeHelper',
|
||||||
|
params.length,
|
||||||
|
path.original,
|
||||||
|
AST.helpers.simpleId(path)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -287,7 +304,13 @@ Compiler.prototype = {
|
|||||||
this.options.data = true;
|
this.options.data = true;
|
||||||
this.opcode('lookupData', path.depth, path.parts, path.strict);
|
this.opcode('lookupData', path.depth, path.parts, path.strict);
|
||||||
} else {
|
} else {
|
||||||
this.opcode('lookupOnContext', path.parts, path.falsy, path.strict, scoped);
|
this.opcode(
|
||||||
|
'lookupOnContext',
|
||||||
|
path.parts,
|
||||||
|
path.falsy,
|
||||||
|
path.strict,
|
||||||
|
scoped
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -329,7 +352,11 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
// HELPERS
|
// HELPERS
|
||||||
opcode: function(name) {
|
opcode: function(name) {
|
||||||
this.opcodes.push({ opcode: name, args: slice.call(arguments, 1), loc: this.sourceNode[0].loc });
|
this.opcodes.push({
|
||||||
|
opcode: name,
|
||||||
|
args: slice.call(arguments, 1),
|
||||||
|
loc: this.sourceNode[0].loc
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
addDepth: function(depth) {
|
addDepth: function(depth) {
|
||||||
@@ -386,9 +413,7 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
if (this.stringParams) {
|
if (this.stringParams) {
|
||||||
if (value.replace) {
|
if (value.replace) {
|
||||||
value = value
|
value = value.replace(/^(\.?\.\/)*/g, '').replace(/\//g, '.');
|
||||||
.replace(/^(\.?\.\/)*/g, '')
|
|
||||||
.replace(/\//g, '.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val.depth) {
|
if (val.depth) {
|
||||||
@@ -444,7 +469,11 @@ Compiler.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
blockParamIndex: function(name) {
|
blockParamIndex: function(name) {
|
||||||
for (let depth = 0, len = this.options.blockParams.length; depth < len; depth++) {
|
for (
|
||||||
|
let depth = 0, len = this.options.blockParams.length;
|
||||||
|
depth < len;
|
||||||
|
depth++
|
||||||
|
) {
|
||||||
let blockParams = this.options.blockParams[depth],
|
let blockParams = this.options.blockParams[depth],
|
||||||
param = blockParams && indexOf(blockParams, name);
|
param = blockParams && indexOf(blockParams, name);
|
||||||
if (blockParams && param >= 0) {
|
if (blockParams && param >= 0) {
|
||||||
@@ -455,8 +484,14 @@ Compiler.prototype = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function precompile(input, options, env) {
|
export function precompile(input, options, env) {
|
||||||
if (input == null || (typeof input !== 'string' && input.type !== 'Program')) {
|
if (
|
||||||
throw new Exception('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input);
|
input == null ||
|
||||||
|
(typeof input !== 'string' && input.type !== 'Program')
|
||||||
|
) {
|
||||||
|
throw new Exception(
|
||||||
|
'You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' +
|
||||||
|
input
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
@@ -473,8 +508,14 @@ export function precompile(input, options, env) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function compile(input, options = {}, env) {
|
export function compile(input, options = {}, env) {
|
||||||
if (input == null || (typeof input !== 'string' && input.type !== 'Program')) {
|
if (
|
||||||
throw new Exception('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input);
|
input == null ||
|
||||||
|
(typeof input !== 'string' && input.type !== 'Program')
|
||||||
|
) {
|
||||||
|
throw new Exception(
|
||||||
|
'You must pass a string or Handlebars AST to Handlebars.compile. You passed ' +
|
||||||
|
input
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
options = extend({}, options);
|
options = extend({}, options);
|
||||||
@@ -490,7 +531,12 @@ export function compile(input, options = {}, env) {
|
|||||||
function compileInput() {
|
function compileInput() {
|
||||||
let ast = env.parse(input, options),
|
let ast = env.parse(input, options),
|
||||||
environment = new env.Compiler().compile(ast, options),
|
environment = new env.Compiler().compile(ast, options),
|
||||||
templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true);
|
templateSpec = new env.JavaScriptCompiler().compile(
|
||||||
|
environment,
|
||||||
|
options,
|
||||||
|
undefined,
|
||||||
|
true
|
||||||
|
);
|
||||||
return env.template(templateSpec);
|
return env.template(templateSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ function validateClose(open, close) {
|
|||||||
if (open.path.original !== close) {
|
if (open.path.original !== close) {
|
||||||
let errorNode = { loc: open.path.loc };
|
let errorNode = { loc: open.path.loc };
|
||||||
|
|
||||||
throw new Exception(open.path.original + " doesn't match " + close, errorNode);
|
throw new Exception(
|
||||||
|
open.path.original + " doesn't match " + close,
|
||||||
|
errorNode
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,8 +41,7 @@ export function stripFlags(open, close) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function stripComment(comment) {
|
export function stripComment(comment) {
|
||||||
return comment.replace(/^\{\{~?!-?-?/, '')
|
return comment.replace(/^\{\{~?!-?-?/, '').replace(/-?-?~?\}\}$/, '');
|
||||||
.replace(/-?-?~?\}\}$/, '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function preparePath(data, parts, loc) {
|
export function preparePath(data, parts, loc) {
|
||||||
@@ -82,7 +84,7 @@ export function prepareMustache(path, params, hash, open, strip, locInfo) {
|
|||||||
let escapeFlag = open.charAt(3) || open.charAt(2),
|
let escapeFlag = open.charAt(3) || open.charAt(2),
|
||||||
escaped = escapeFlag !== '{' && escapeFlag !== '&';
|
escaped = escapeFlag !== '{' && escapeFlag !== '&';
|
||||||
|
|
||||||
let decorator = (/\*/.test(open));
|
let decorator = /\*/.test(open);
|
||||||
return {
|
return {
|
||||||
type: decorator ? 'Decorator' : 'MustacheStatement',
|
type: decorator ? 'Decorator' : 'MustacheStatement',
|
||||||
path,
|
path,
|
||||||
@@ -118,21 +120,30 @@ export function prepareRawBlock(openRawBlock, contents, close, locInfo) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) {
|
export function prepareBlock(
|
||||||
|
openBlock,
|
||||||
|
program,
|
||||||
|
inverseAndProgram,
|
||||||
|
close,
|
||||||
|
inverted,
|
||||||
|
locInfo
|
||||||
|
) {
|
||||||
if (close && close.path) {
|
if (close && close.path) {
|
||||||
validateClose(openBlock, close);
|
validateClose(openBlock, close);
|
||||||
}
|
}
|
||||||
|
|
||||||
let decorator = (/\*/.test(openBlock.open));
|
let decorator = /\*/.test(openBlock.open);
|
||||||
|
|
||||||
program.blockParams = openBlock.blockParams;
|
program.blockParams = openBlock.blockParams;
|
||||||
|
|
||||||
let inverse,
|
let inverse, inverseStrip;
|
||||||
inverseStrip;
|
|
||||||
|
|
||||||
if (inverseAndProgram) {
|
if (inverseAndProgram) {
|
||||||
if (decorator) {
|
if (decorator) {
|
||||||
throw new Exception('Unexpected inverse block on decorator', inverseAndProgram);
|
throw new Exception(
|
||||||
|
'Unexpected inverse block on decorator',
|
||||||
|
inverseAndProgram
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inverseAndProgram.chain) {
|
if (inverseAndProgram.chain) {
|
||||||
@@ -192,7 +203,6 @@ export function prepareProgram(statements, loc) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function preparePartialBlock(open, program, close, locInfo) {
|
export function preparePartialBlock(open, program, close, locInfo) {
|
||||||
validateClose(open, close);
|
validateClose(open, close);
|
||||||
|
|
||||||
@@ -207,4 +217,3 @@ export function preparePartialBlock(open, program, close, locInfo) {
|
|||||||
loc: this.locInfo(locInfo)
|
loc: this.locInfo(locInfo)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,14 @@ JavaScriptCompiler.prototype = {
|
|||||||
// 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*/) {
|
||||||
if (dangerousPropertyRegex.test(name)) {
|
if (dangerousPropertyRegex.test(name)) {
|
||||||
const isEnumerable = [ this.aliasable('container.propertyIsEnumerable'), '.call(', parent, ',', JSON.stringify(name), ')'];
|
const isEnumerable = [
|
||||||
|
this.aliasable('container.propertyIsEnumerable'),
|
||||||
|
'.call(',
|
||||||
|
parent,
|
||||||
|
',',
|
||||||
|
JSON.stringify(name),
|
||||||
|
')'
|
||||||
|
];
|
||||||
return ['(', isEnumerable, '?', _actualLookup(), ' : undefined)'];
|
return ['(', isEnumerable, '?', _actualLookup(), ' : undefined)'];
|
||||||
}
|
}
|
||||||
return _actualLookup();
|
return _actualLookup();
|
||||||
@@ -91,7 +98,11 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
this.compileChildren(environment, options);
|
this.compileChildren(environment, options);
|
||||||
|
|
||||||
this.useDepths = this.useDepths || environment.useDepths || environment.useDecorators || this.options.compat;
|
this.useDepths =
|
||||||
|
this.useDepths ||
|
||||||
|
environment.useDepths ||
|
||||||
|
environment.useDecorators ||
|
||||||
|
this.options.compat;
|
||||||
this.useBlockParams = this.useBlockParams || environment.useBlockParams;
|
this.useBlockParams = this.useBlockParams || environment.useBlockParams;
|
||||||
|
|
||||||
let opcodes = environment.opcodes,
|
let opcodes = environment.opcodes,
|
||||||
@@ -124,9 +135,20 @@ JavaScriptCompiler.prototype = {
|
|||||||
this.decorators.push('return fn;');
|
this.decorators.push('return fn;');
|
||||||
|
|
||||||
if (asObject) {
|
if (asObject) {
|
||||||
this.decorators = Function.apply(this, ['fn', 'props', 'container', 'depth0', 'data', 'blockParams', 'depths', this.decorators.merge()]);
|
this.decorators = Function.apply(this, [
|
||||||
|
'fn',
|
||||||
|
'props',
|
||||||
|
'container',
|
||||||
|
'depth0',
|
||||||
|
'data',
|
||||||
|
'blockParams',
|
||||||
|
'depths',
|
||||||
|
this.decorators.merge()
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
this.decorators.prepend('function(fn, props, container, depth0, data, blockParams, depths) {\n');
|
this.decorators.prepend(
|
||||||
|
'function(fn, props, container, depth0, data, blockParams, depths) {\n'
|
||||||
|
);
|
||||||
this.decorators.push('}\n');
|
this.decorators.push('}\n');
|
||||||
this.decorators = this.decorators.merge();
|
this.decorators = this.decorators.merge();
|
||||||
}
|
}
|
||||||
@@ -221,7 +243,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
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;
|
||||||
node.children[0] = 'alias' + aliasCount;
|
node.children[0] = 'alias' + aliasCount;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -243,18 +265,23 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
return Function.apply(this, params);
|
return Function.apply(this, params);
|
||||||
} else {
|
} else {
|
||||||
return this.source.wrap(['function(', params.join(','), ') {\n ', source, '}']);
|
return this.source.wrap([
|
||||||
|
'function(',
|
||||||
|
params.join(','),
|
||||||
|
') {\n ',
|
||||||
|
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(' + ');
|
||||||
@@ -280,7 +307,6 @@ JavaScriptCompiler.prototype = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (appendOnly) {
|
if (appendOnly) {
|
||||||
if (bufferStart) {
|
if (bufferStart) {
|
||||||
bufferStart.prepend('return ');
|
bufferStart.prepend('return ');
|
||||||
@@ -289,7 +315,8 @@ JavaScriptCompiler.prototype = {
|
|||||||
this.source.push('return "";');
|
this.source.push('return "";');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer());
|
varDeclarations +=
|
||||||
|
', buffer = ' + (appendFirst ? '' : this.initializeBuffer());
|
||||||
|
|
||||||
if (bufferStart) {
|
if (bufferStart) {
|
||||||
bufferStart.prepend('return buffer + ');
|
bufferStart.prepend('return buffer + ');
|
||||||
@@ -300,7 +327,9 @@ JavaScriptCompiler.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (varDeclarations) {
|
if (varDeclarations) {
|
||||||
this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n'));
|
this.source.prepend(
|
||||||
|
'var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.source.merge();
|
return this.source.merge();
|
||||||
@@ -316,7 +345,9 @@ JavaScriptCompiler.prototype = {
|
|||||||
// 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('container.hooks.blockHelperMissing'),
|
let blockHelperMissing = this.aliasable(
|
||||||
|
'container.hooks.blockHelperMissing'
|
||||||
|
),
|
||||||
params = [this.contextName(0)];
|
params = [this.contextName(0)];
|
||||||
this.setupHelperArgs(name, 0, params);
|
this.setupHelperArgs(name, 0, params);
|
||||||
|
|
||||||
@@ -334,7 +365,9 @@ JavaScriptCompiler.prototype = {
|
|||||||
// 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('container.hooks.blockHelperMissing'),
|
let blockHelperMissing = this.aliasable(
|
||||||
|
'container.hooks.blockHelperMissing'
|
||||||
|
),
|
||||||
params = [this.contextName(0)];
|
params = [this.contextName(0)];
|
||||||
this.setupHelperArgs('', 0, params, true);
|
this.setupHelperArgs('', 0, params, true);
|
||||||
|
|
||||||
@@ -344,9 +377,14 @@ JavaScriptCompiler.prototype = {
|
|||||||
params.splice(1, 0, current);
|
params.splice(1, 0, current);
|
||||||
|
|
||||||
this.pushSource([
|
this.pushSource([
|
||||||
'if (!', this.lastHelper, ') { ',
|
'if (!',
|
||||||
current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params),
|
this.lastHelper,
|
||||||
'}']);
|
') { ',
|
||||||
|
current,
|
||||||
|
' = ',
|
||||||
|
this.source.functionCall(blockHelperMissing, 'call', params),
|
||||||
|
'}'
|
||||||
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
// [appendContent]
|
// [appendContent]
|
||||||
@@ -376,14 +414,24 @@ JavaScriptCompiler.prototype = {
|
|||||||
// 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 {
|
||||||
let local = this.popStack();
|
let local = this.popStack();
|
||||||
this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']);
|
this.pushSource([
|
||||||
|
'if (',
|
||||||
|
local,
|
||||||
|
' != null) { ',
|
||||||
|
this.appendToBuffer(local, undefined, true),
|
||||||
|
' }'
|
||||||
|
]);
|
||||||
if (this.environment.isSimple) {
|
if (this.environment.isSimple) {
|
||||||
this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']);
|
this.pushSource([
|
||||||
|
'else { ',
|
||||||
|
this.appendToBuffer("''", undefined, true),
|
||||||
|
' }'
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -395,8 +443,14 @@ JavaScriptCompiler.prototype = {
|
|||||||
//
|
//
|
||||||
// Escape `value` and append it to the buffer
|
// Escape `value` and append it to the buffer
|
||||||
appendEscaped: function() {
|
appendEscaped: function() {
|
||||||
this.pushSource(this.appendToBuffer(
|
this.pushSource(
|
||||||
[this.aliasable('container.escapeExpression'), '(', this.popStack(), ')']));
|
this.appendToBuffer([
|
||||||
|
this.aliasable('container.escapeExpression'),
|
||||||
|
'(',
|
||||||
|
this.popStack(),
|
||||||
|
')'
|
||||||
|
])
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
// [getContext]
|
// [getContext]
|
||||||
@@ -480,7 +534,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.
|
||||||
@@ -503,7 +557,14 @@ 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.aliasable('container.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']);
|
this.push([
|
||||||
|
this.aliasable('container.lambda'),
|
||||||
|
'(',
|
||||||
|
this.popStack(),
|
||||||
|
', ',
|
||||||
|
this.contextName(0),
|
||||||
|
')'
|
||||||
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
// [pushStringParam]
|
// [pushStringParam]
|
||||||
@@ -611,7 +672,12 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
this.decorators.push([
|
this.decorators.push([
|
||||||
'fn = ',
|
'fn = ',
|
||||||
this.decorators.functionCall(foundDecorator, '', ['fn', 'props', 'container', options]),
|
this.decorators.functionCall(foundDecorator, '', [
|
||||||
|
'fn',
|
||||||
|
'props',
|
||||||
|
'container',
|
||||||
|
options
|
||||||
|
]),
|
||||||
' || fn;'
|
' || fn;'
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
@@ -631,17 +697,28 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
let possibleFunctionCalls = [];
|
let possibleFunctionCalls = [];
|
||||||
|
|
||||||
if (isSimple) { // direct call to helper
|
if (isSimple) {
|
||||||
|
// direct call to helper
|
||||||
possibleFunctionCalls.push(helper.name);
|
possibleFunctionCalls.push(helper.name);
|
||||||
}
|
}
|
||||||
// call a function from the input object
|
// call a function from the input object
|
||||||
possibleFunctionCalls.push(nonHelper);
|
possibleFunctionCalls.push(nonHelper);
|
||||||
if (!this.options.strict) {
|
if (!this.options.strict) {
|
||||||
possibleFunctionCalls.push(this.aliasable('container.hooks.helperMissing'));
|
possibleFunctionCalls.push(
|
||||||
|
this.aliasable('container.hooks.helperMissing')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let functionLookupCode = ['(', this.itemsSeparatedBy(possibleFunctionCalls, '||'), ')'];
|
let functionLookupCode = [
|
||||||
let functionCall = this.source.functionCall(functionLookupCode, 'call', helper.callParams);
|
'(',
|
||||||
|
this.itemsSeparatedBy(possibleFunctionCalls, '||'),
|
||||||
|
')'
|
||||||
|
];
|
||||||
|
let functionCall = this.source.functionCall(
|
||||||
|
functionLookupCode,
|
||||||
|
'call',
|
||||||
|
helper.callParams
|
||||||
|
);
|
||||||
this.push(functionCall);
|
this.push(functionCall);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -685,7 +762,11 @@ JavaScriptCompiler.prototype = {
|
|||||||
this.emptyHash();
|
this.emptyHash();
|
||||||
let helper = this.setupHelper(0, name, helperCall);
|
let helper = this.setupHelper(0, name, helperCall);
|
||||||
|
|
||||||
let helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
|
let helperName = (this.lastHelper = this.nameLookup(
|
||||||
|
'helpers',
|
||||||
|
name,
|
||||||
|
'helper'
|
||||||
|
));
|
||||||
|
|
||||||
let lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')'];
|
let lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')'];
|
||||||
if (!this.options.strict) {
|
if (!this.options.strict) {
|
||||||
@@ -697,10 +778,15 @@ JavaScriptCompiler.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.push([
|
this.push([
|
||||||
'(', lookup,
|
'(',
|
||||||
(helper.paramsInit ? ['),(', helper.paramsInit] : []), '),',
|
lookup,
|
||||||
'(typeof helper === ', this.aliasable('"function"'), ' ? ',
|
helper.paramsInit ? ['),(', helper.paramsInit] : [],
|
||||||
this.source.functionCall('helper', 'call', helper.callParams), ' : helper))'
|
'),',
|
||||||
|
'(typeof helper === ',
|
||||||
|
this.aliasable('"function"'),
|
||||||
|
' ? ',
|
||||||
|
this.source.functionCall('helper', 'call', helper.callParams),
|
||||||
|
' : helper))'
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -778,8 +864,13 @@ JavaScriptCompiler.prototype = {
|
|||||||
pushId: function(type, name, child) {
|
pushId: function(type, name, child) {
|
||||||
if (type === 'BlockParam') {
|
if (type === 'BlockParam') {
|
||||||
this.pushStackLiteral(
|
this.pushStackLiteral(
|
||||||
'blockParams[' + name[0] + '].path[' + name[1] + ']'
|
'blockParams[' +
|
||||||
+ (child ? ' + ' + JSON.stringify('.' + child) : ''));
|
name[0] +
|
||||||
|
'].path[' +
|
||||||
|
name[1] +
|
||||||
|
']' +
|
||||||
|
(child ? ' + ' + JSON.stringify('.' + child) : '')
|
||||||
|
);
|
||||||
} else if (type === 'PathExpression') {
|
} else if (type === 'PathExpression') {
|
||||||
this.pushString(name);
|
this.pushString(name);
|
||||||
} else if (type === 'SubExpression') {
|
} else if (type === 'SubExpression') {
|
||||||
@@ -794,7 +885,9 @@ JavaScriptCompiler.prototype = {
|
|||||||
compiler: JavaScriptCompiler,
|
compiler: JavaScriptCompiler,
|
||||||
|
|
||||||
compileChildren: function(environment, options) {
|
compileChildren: function(environment, options) {
|
||||||
let children = environment.children, child, compiler;
|
let children = environment.children,
|
||||||
|
child,
|
||||||
|
compiler;
|
||||||
|
|
||||||
for (let i = 0, l = children.length; i < l; i++) {
|
for (let i = 0, l = children.length; i < l; i++) {
|
||||||
child = children[i];
|
child = children[i];
|
||||||
@@ -807,7 +900,12 @@ JavaScriptCompiler.prototype = {
|
|||||||
let index = this.context.programs.length;
|
let index = this.context.programs.length;
|
||||||
child.index = index;
|
child.index = index;
|
||||||
child.name = 'program' + index;
|
child.name = 'program' + index;
|
||||||
this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile);
|
this.context.programs[index] = compiler.compile(
|
||||||
|
child,
|
||||||
|
options,
|
||||||
|
this.context,
|
||||||
|
!this.precompile
|
||||||
|
);
|
||||||
this.context.decorators[index] = compiler.decorators;
|
this.context.decorators[index] = compiler.decorators;
|
||||||
this.context.environments[index] = child;
|
this.context.environments[index] = child;
|
||||||
|
|
||||||
@@ -870,7 +968,11 @@ JavaScriptCompiler.prototype = {
|
|||||||
pushSource: function(source) {
|
pushSource: function(source) {
|
||||||
if (this.pendingContent) {
|
if (this.pendingContent) {
|
||||||
this.source.push(
|
this.source.push(
|
||||||
this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation));
|
this.appendToBuffer(
|
||||||
|
this.source.quotedString(this.pendingContent),
|
||||||
|
this.pendingLocation
|
||||||
|
)
|
||||||
|
);
|
||||||
this.pendingContent = undefined;
|
this.pendingContent = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -920,7 +1022,9 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
incrStack: function() {
|
incrStack: function() {
|
||||||
this.stackSlot++;
|
this.stackSlot++;
|
||||||
if (this.stackSlot > this.stackVars.length) { this.stackVars.push('stack' + this.stackSlot); }
|
if (this.stackSlot > this.stackVars.length) {
|
||||||
|
this.stackVars.push('stack' + this.stackSlot);
|
||||||
|
}
|
||||||
return this.topStackName();
|
return this.topStackName();
|
||||||
},
|
},
|
||||||
topStackName: function() {
|
topStackName: function() {
|
||||||
@@ -949,7 +1053,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
let inline = this.isInline(),
|
let inline = this.isInline(),
|
||||||
item = (inline ? this.inlineStack : this.compileStack).pop();
|
item = (inline ? this.inlineStack : this.compileStack).pop();
|
||||||
|
|
||||||
if (!wrapped && (item instanceof Literal)) {
|
if (!wrapped && item instanceof Literal) {
|
||||||
return item.value;
|
return item.value;
|
||||||
} else {
|
} else {
|
||||||
if (!inline) {
|
if (!inline) {
|
||||||
@@ -964,7 +1068,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];
|
||||||
|
|
||||||
/* istanbul ignore if */
|
/* istanbul ignore if */
|
||||||
@@ -1009,7 +1113,11 @@ JavaScriptCompiler.prototype = {
|
|||||||
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'),
|
||||||
callContext = this.aliasable(`${this.contextName(0)} != null ? ${this.contextName(0)} : (container.nullContext || {})`);
|
callContext = this.aliasable(
|
||||||
|
`${this.contextName(0)} != null ? ${this.contextName(
|
||||||
|
0
|
||||||
|
)} : (container.nullContext || {})`
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
params: params,
|
params: params,
|
||||||
@@ -1106,7 +1214,6 @@ JavaScriptCompiler.prototype = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
const reservedWords = (
|
const reservedWords = (
|
||||||
'break else new var' +
|
'break else new var' +
|
||||||
@@ -1127,15 +1234,18 @@ JavaScriptCompiler.prototype = {
|
|||||||
' null true false'
|
' null true false'
|
||||||
).split(' ');
|
).split(' ');
|
||||||
|
|
||||||
const compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
|
const compilerWords = (JavaScriptCompiler.RESERVED_WORDS = {});
|
||||||
|
|
||||||
for (let i = 0, l = reservedWords.length; i < l; i++) {
|
for (let i = 0, l = reservedWords.length; i < l; i++) {
|
||||||
compilerWords[reservedWords[i]] = true;
|
compilerWords[reservedWords[i]] = true;
|
||||||
}
|
}
|
||||||
}());
|
})();
|
||||||
|
|
||||||
JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
|
JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
|
||||||
return !JavaScriptCompiler.RESERVED_WORDS[name] && (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/).test(name);
|
return (
|
||||||
|
!JavaScriptCompiler.RESERVED_WORDS[name] &&
|
||||||
|
/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function strictLookup(requireTerminal, compiler, parts, type) {
|
function strictLookup(requireTerminal, compiler, parts, type) {
|
||||||
@@ -1151,7 +1261,16 @@ function strictLookup(requireTerminal, compiler, parts, type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (requireTerminal) {
|
if (requireTerminal) {
|
||||||
return [compiler.aliasable('container.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ', ', JSON.stringify(compiler.source.currentLocation), ' )'];
|
return [
|
||||||
|
compiler.aliasable('container.strict'),
|
||||||
|
'(',
|
||||||
|
stack,
|
||||||
|
', ',
|
||||||
|
compiler.quotedString(parts[i]),
|
||||||
|
', ',
|
||||||
|
JSON.stringify(compiler.source.currentLocation),
|
||||||
|
' )'
|
||||||
|
];
|
||||||
} else {
|
} else {
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ PrintVisitor.prototype.pad = function(string) {
|
|||||||
PrintVisitor.prototype.Program = function(program) {
|
PrintVisitor.prototype.Program = function(program) {
|
||||||
let out = '',
|
let out = '',
|
||||||
body = program.body,
|
body = program.body,
|
||||||
i, l;
|
i,
|
||||||
|
l;
|
||||||
|
|
||||||
if (program.blockParams) {
|
if (program.blockParams) {
|
||||||
let blockParams = 'BLOCK PARAMS: [';
|
let blockParams = 'BLOCK PARAMS: [';
|
||||||
@@ -52,11 +53,14 @@ PrintVisitor.prototype.Decorator = function(mustache) {
|
|||||||
return this.pad('{{ DIRECTIVE ' + this.SubExpression(mustache) + ' }}');
|
return this.pad('{{ DIRECTIVE ' + this.SubExpression(mustache) + ' }}');
|
||||||
};
|
};
|
||||||
|
|
||||||
PrintVisitor.prototype.BlockStatement =
|
PrintVisitor.prototype.BlockStatement = PrintVisitor.prototype.DecoratorBlock = function(
|
||||||
PrintVisitor.prototype.DecoratorBlock = function(block) {
|
block
|
||||||
|
) {
|
||||||
let out = '';
|
let out = '';
|
||||||
|
|
||||||
out += this.pad((block.type === 'DecoratorBlock' ? 'DIRECTIVE ' : '') + 'BLOCK:');
|
out += this.pad(
|
||||||
|
(block.type === 'DecoratorBlock' ? 'DIRECTIVE ' : '') + 'BLOCK:'
|
||||||
|
);
|
||||||
this.padding++;
|
this.padding++;
|
||||||
out += this.pad(this.SubExpression(block));
|
out += this.pad(this.SubExpression(block));
|
||||||
if (block.program) {
|
if (block.program) {
|
||||||
@@ -66,12 +70,16 @@ PrintVisitor.prototype.DecoratorBlock = function(block) {
|
|||||||
this.padding--;
|
this.padding--;
|
||||||
}
|
}
|
||||||
if (block.inverse) {
|
if (block.inverse) {
|
||||||
if (block.program) { this.padding++; }
|
if (block.program) {
|
||||||
|
this.padding++;
|
||||||
|
}
|
||||||
out += this.pad('{{^}}');
|
out += this.pad('{{^}}');
|
||||||
this.padding++;
|
this.padding++;
|
||||||
out += this.accept(block.inverse);
|
out += this.accept(block.inverse);
|
||||||
this.padding--;
|
this.padding--;
|
||||||
if (block.program) { this.padding--; }
|
if (block.program) {
|
||||||
|
this.padding--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.padding--;
|
this.padding--;
|
||||||
|
|
||||||
@@ -134,7 +142,6 @@ PrintVisitor.prototype.PathExpression = function(id) {
|
|||||||
return (id.data ? '@' : '') + 'PATH:' + path;
|
return (id.data ? '@' : '') + 'PATH:' + path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
PrintVisitor.prototype.StringLiteral = function(string) {
|
PrintVisitor.prototype.StringLiteral = function(string) {
|
||||||
return '"' + string.value + '"';
|
return '"' + string.value + '"';
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,14 @@ Visitor.prototype = {
|
|||||||
// Hacky sanity check: This may have a few false positives for type for the helper
|
// Hacky sanity check: This may have a few false positives for type for the helper
|
||||||
// methods but will generally do the right thing without a lot of overhead.
|
// methods but will generally do the right thing without a lot of overhead.
|
||||||
if (value && !Visitor.prototype[value.type]) {
|
if (value && !Visitor.prototype[value.type]) {
|
||||||
throw new Exception('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type);
|
throw new Exception(
|
||||||
|
'Unexpected node type "' +
|
||||||
|
value.type +
|
||||||
|
'" found when accepting ' +
|
||||||
|
name +
|
||||||
|
' on ' +
|
||||||
|
node.type
|
||||||
|
);
|
||||||
}
|
}
|
||||||
node[name] = value;
|
node[name] = value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ WhitespaceControl.prototype.Program = function(program) {
|
|||||||
|
|
||||||
let _isPrevWhitespace = isPrevWhitespace(body, i, isRoot),
|
let _isPrevWhitespace = isPrevWhitespace(body, i, isRoot),
|
||||||
_isNextWhitespace = isNextWhitespace(body, i, isRoot),
|
_isNextWhitespace = isNextWhitespace(body, i, isRoot),
|
||||||
|
|
||||||
openStandalone = strip.openStandalone && _isPrevWhitespace,
|
openStandalone = strip.openStandalone && _isPrevWhitespace,
|
||||||
closeStandalone = strip.closeStandalone && _isNextWhitespace,
|
closeStandalone = strip.closeStandalone && _isNextWhitespace,
|
||||||
inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace;
|
inlineStandalone =
|
||||||
|
strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace;
|
||||||
|
|
||||||
if (strip.close) {
|
if (strip.close) {
|
||||||
omitRight(body, i, true);
|
omitRight(body, i, true);
|
||||||
@@ -41,7 +41,7 @@ WhitespaceControl.prototype.Program = function(program) {
|
|||||||
// If we are on a standalone node, save the indent info for partials
|
// If we are on a standalone node, save the indent info for partials
|
||||||
if (current.type === 'PartialStatement') {
|
if (current.type === 'PartialStatement') {
|
||||||
// Pull out the whitespace from the final line
|
// Pull out the whitespace from the final line
|
||||||
current.indent = (/([ \t]+$)/).exec(body[i - 1].original)[1];
|
current.indent = /([ \t]+$)/.exec(body[i - 1].original)[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,9 +62,9 @@ WhitespaceControl.prototype.Program = function(program) {
|
|||||||
return program;
|
return program;
|
||||||
};
|
};
|
||||||
|
|
||||||
WhitespaceControl.prototype.BlockStatement =
|
WhitespaceControl.prototype.BlockStatement = WhitespaceControl.prototype.DecoratorBlock = WhitespaceControl.prototype.PartialBlockStatement = function(
|
||||||
WhitespaceControl.prototype.DecoratorBlock =
|
block
|
||||||
WhitespaceControl.prototype.PartialBlockStatement = function(block) {
|
) {
|
||||||
this.accept(block.program);
|
this.accept(block.program);
|
||||||
this.accept(block.inverse);
|
this.accept(block.inverse);
|
||||||
|
|
||||||
@@ -112,9 +112,11 @@ WhitespaceControl.prototype.PartialBlockStatement = function(block) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find standalone else statments
|
// Find standalone else statments
|
||||||
if (!this.options.ignoreStandalone
|
if (
|
||||||
&& isPrevWhitespace(program.body)
|
!this.options.ignoreStandalone &&
|
||||||
&& isNextWhitespace(firstInverse.body)) {
|
isPrevWhitespace(program.body) &&
|
||||||
|
isNextWhitespace(firstInverse.body)
|
||||||
|
) {
|
||||||
omitLeft(program.body);
|
omitLeft(program.body);
|
||||||
omitRight(firstInverse.body);
|
omitRight(firstInverse.body);
|
||||||
}
|
}
|
||||||
@@ -125,13 +127,15 @@ WhitespaceControl.prototype.PartialBlockStatement = function(block) {
|
|||||||
return strip;
|
return strip;
|
||||||
};
|
};
|
||||||
|
|
||||||
WhitespaceControl.prototype.Decorator =
|
WhitespaceControl.prototype.Decorator = WhitespaceControl.prototype.MustacheStatement = function(
|
||||||
WhitespaceControl.prototype.MustacheStatement = function(mustache) {
|
mustache
|
||||||
|
) {
|
||||||
return mustache.strip;
|
return mustache.strip;
|
||||||
};
|
};
|
||||||
|
|
||||||
WhitespaceControl.prototype.PartialStatement =
|
WhitespaceControl.prototype.PartialStatement = WhitespaceControl.prototype.CommentStatement = function(
|
||||||
WhitespaceControl.prototype.CommentStatement = function(node) {
|
node
|
||||||
|
) {
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
let strip = node.strip || {};
|
let strip = node.strip || {};
|
||||||
return {
|
return {
|
||||||
@@ -141,7 +145,6 @@ WhitespaceControl.prototype.PartialStatement =
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function isPrevWhitespace(body, i, isRoot) {
|
function isPrevWhitespace(body, i, isRoot) {
|
||||||
if (i === undefined) {
|
if (i === undefined) {
|
||||||
i = body.length;
|
i = body.length;
|
||||||
@@ -156,7 +159,9 @@ function isPrevWhitespace(body, i, isRoot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (prev.type === 'ContentStatement') {
|
if (prev.type === 'ContentStatement') {
|
||||||
return (sibling || !isRoot ? (/\r?\n\s*?$/) : (/(^|\r?\n)\s*?$/)).test(prev.original);
|
return (sibling || !isRoot ? /\r?\n\s*?$/ : /(^|\r?\n)\s*?$/).test(
|
||||||
|
prev.original
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function isNextWhitespace(body, i, isRoot) {
|
function isNextWhitespace(body, i, isRoot) {
|
||||||
@@ -171,7 +176,9 @@ function isNextWhitespace(body, i, isRoot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (next.type === 'ContentStatement') {
|
if (next.type === 'ContentStatement') {
|
||||||
return (sibling || !isRoot ? (/^\s*?\r?\n/) : (/^\s*?(\r?\n|$)/)).test(next.original);
|
return (sibling || !isRoot ? /^\s*?\r?\n/ : /^\s*?(\r?\n|$)/).test(
|
||||||
|
next.original
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,12 +191,19 @@ function isNextWhitespace(body, i, isRoot) {
|
|||||||
// content is met.
|
// content is met.
|
||||||
function omitRight(body, i, multiple) {
|
function omitRight(body, i, multiple) {
|
||||||
let current = body[i == null ? 0 : i + 1];
|
let current = body[i == null ? 0 : i + 1];
|
||||||
if (!current || current.type !== 'ContentStatement' || (!multiple && current.rightStripped)) {
|
if (
|
||||||
|
!current ||
|
||||||
|
current.type !== 'ContentStatement' ||
|
||||||
|
(!multiple && current.rightStripped)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let original = current.value;
|
let original = current.value;
|
||||||
current.value = current.value.replace(multiple ? (/^\s+/) : (/^[ \t]*\r?\n?/), '');
|
current.value = current.value.replace(
|
||||||
|
multiple ? /^\s+/ : /^[ \t]*\r?\n?/,
|
||||||
|
''
|
||||||
|
);
|
||||||
current.rightStripped = current.value !== original;
|
current.rightStripped = current.value !== original;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,13 +216,17 @@ function omitRight(body, i, multiple) {
|
|||||||
// content is met.
|
// content is met.
|
||||||
function omitLeft(body, i, multiple) {
|
function omitLeft(body, i, multiple) {
|
||||||
let current = body[i == null ? body.length - 1 : i - 1];
|
let current = body[i == null ? body.length - 1 : i - 1];
|
||||||
if (!current || current.type !== 'ContentStatement' || (!multiple && current.leftStripped)) {
|
if (
|
||||||
|
!current ||
|
||||||
|
current.type !== 'ContentStatement' ||
|
||||||
|
(!multiple && current.leftStripped)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We omit the last node if it's whitespace only and not preceded by a non-content node.
|
// We omit the last node if it's whitespace only and not preceded by a non-content node.
|
||||||
let original = current.value;
|
let original = current.value;
|
||||||
current.value = current.value.replace(multiple ? (/\s+$/) : (/[ \t]+$/), '');
|
current.value = current.value.replace(multiple ? /\s+$/ : /[ \t]+$/, '');
|
||||||
current.leftStripped = current.value !== original;
|
current.leftStripped = current.value !== original;
|
||||||
return current.leftStripped;
|
return current.leftStripped;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,4 +3,3 @@ import registerInline from './decorators/inline';
|
|||||||
export function registerDefaultDecorators(instance) {
|
export function registerDefaultDecorators(instance) {
|
||||||
registerInline(instance);
|
registerInline(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
|
const errorProps = [
|
||||||
const errorProps = ['description', 'fileName', 'lineNumber', 'endLineNumber', 'message', 'name', 'number', 'stack'];
|
'description',
|
||||||
|
'fileName',
|
||||||
|
'lineNumber',
|
||||||
|
'endLineNumber',
|
||||||
|
'message',
|
||||||
|
'name',
|
||||||
|
'number',
|
||||||
|
'stack'
|
||||||
|
];
|
||||||
|
|
||||||
function Exception(message, node) {
|
function Exception(message, node) {
|
||||||
let loc = node && node.loc,
|
let loc = node && node.loc,
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ export default function(instance) {
|
|||||||
} else {
|
} else {
|
||||||
if (options.data && options.ids) {
|
if (options.data && options.ids) {
|
||||||
let data = createFrame(options.data);
|
let data = createFrame(options.data);
|
||||||
data.contextPath = appendContextPath(options.data.contextPath, options.name);
|
data.contextPath = appendContextPath(
|
||||||
|
options.data.contextPath,
|
||||||
|
options.name
|
||||||
|
);
|
||||||
options = { data: data };
|
options = { data: data };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import {appendContextPath, blockParams, createFrame, isArray, isFunction} from '../utils';
|
import {
|
||||||
|
appendContextPath,
|
||||||
|
blockParams,
|
||||||
|
createFrame,
|
||||||
|
isArray,
|
||||||
|
isFunction
|
||||||
|
} from '../utils';
|
||||||
import Exception from '../exception';
|
import Exception from '../exception';
|
||||||
|
|
||||||
export default function(instance) {
|
export default function(instance) {
|
||||||
@@ -15,10 +21,13 @@ export default function(instance) {
|
|||||||
contextPath;
|
contextPath;
|
||||||
|
|
||||||
if (options.data && options.ids) {
|
if (options.data && options.ids) {
|
||||||
contextPath = appendContextPath(options.data.contextPath, options.ids[0]) + '.';
|
contextPath =
|
||||||
|
appendContextPath(options.data.contextPath, options.ids[0]) + '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFunction(context)) { context = context.call(this); }
|
if (isFunction(context)) {
|
||||||
|
context = context.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (options.data) {
|
if (options.data) {
|
||||||
data = createFrame(options.data);
|
data = createFrame(options.data);
|
||||||
@@ -36,9 +45,14 @@ export default function(instance) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ret + fn(context[field], {
|
ret =
|
||||||
|
ret +
|
||||||
|
fn(context[field], {
|
||||||
data: data,
|
data: data,
|
||||||
blockParams: blockParams([context[field], field], [contextPath + field, null])
|
blockParams: blockParams(
|
||||||
|
[context[field], field],
|
||||||
|
[contextPath + field, null]
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ export default function(instance) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
} else {
|
} else {
|
||||||
// Someone is actually trying to call something, blow up.
|
// Someone is actually trying to call something, blow up.
|
||||||
throw new Exception('Missing helper: "' + arguments[arguments.length - 1].name + '"');
|
throw new Exception(
|
||||||
|
'Missing helper: "' + arguments[arguments.length - 1].name + '"'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,12 @@ import Exception from '../exception';
|
|||||||
|
|
||||||
export default function(instance) {
|
export default function(instance) {
|
||||||
instance.registerHelper('if', function(conditional, options) {
|
instance.registerHelper('if', function(conditional, options) {
|
||||||
if (arguments.length != 2) { throw new Exception('#if requires exactly one argument');}
|
if (arguments.length != 2) {
|
||||||
if (isFunction(conditional)) { conditional = conditional.call(this); }
|
throw new Exception('#if requires exactly one argument');
|
||||||
|
}
|
||||||
|
if (isFunction(conditional)) {
|
||||||
|
conditional = conditional.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
// Default behavior is to render the positive path if the value is truthy and not empty.
|
// Default behavior is to render the positive path if the value is truthy and not empty.
|
||||||
// The `includeZero` option may be set to treat the condtional as purely not empty based on the
|
// The `includeZero` option may be set to treat the condtional as purely not empty based on the
|
||||||
@@ -17,7 +21,13 @@ export default function(instance) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
instance.registerHelper('unless', function(conditional, options) {
|
instance.registerHelper('unless', function(conditional, options) {
|
||||||
if (arguments.length != 2) { throw new Exception('#unless requires exactly one argument');}
|
if (arguments.length != 2) {
|
||||||
return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash});
|
throw new Exception('#unless requires exactly one argument');
|
||||||
|
}
|
||||||
|
return instance.helpers['if'].call(this, conditional, {
|
||||||
|
fn: options.inverse,
|
||||||
|
inverse: options.fn,
|
||||||
|
hash: options.hash
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,10 @@ export default function(instance) {
|
|||||||
if (!obj) {
|
if (!obj) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
if (dangerousPropertyRegex.test(String(field)) && !Object.prototype.propertyIsEnumerable.call(obj, field)) {
|
if (
|
||||||
|
dangerousPropertyRegex.test(String(field)) &&
|
||||||
|
!Object.prototype.propertyIsEnumerable.call(obj, field)
|
||||||
|
) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return obj[field];
|
return obj[field];
|
||||||
|
|||||||
@@ -1,10 +1,20 @@
|
|||||||
import { appendContextPath, blockParams, createFrame, isEmpty, isFunction } from '../utils';
|
import {
|
||||||
|
appendContextPath,
|
||||||
|
blockParams,
|
||||||
|
createFrame,
|
||||||
|
isEmpty,
|
||||||
|
isFunction
|
||||||
|
} from '../utils';
|
||||||
import Exception from '../exception';
|
import Exception from '../exception';
|
||||||
|
|
||||||
export default function(instance) {
|
export default function(instance) {
|
||||||
instance.registerHelper('with', function(context, options) {
|
instance.registerHelper('with', function(context, options) {
|
||||||
if (arguments.length != 2) { throw new Exception('#with requires exactly one argument');}
|
if (arguments.length != 2) {
|
||||||
if (isFunction(context)) { context = context.call(this); }
|
throw new Exception('#with requires exactly one argument');
|
||||||
|
}
|
||||||
|
if (isFunction(context)) {
|
||||||
|
context = context.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
let fn = options.fn;
|
let fn = options.fn;
|
||||||
|
|
||||||
@@ -12,7 +22,10 @@ export default function(instance) {
|
|||||||
let data = options.data;
|
let data = options.data;
|
||||||
if (options.data && options.ids) {
|
if (options.data && options.ids) {
|
||||||
data = createFrame(options.data);
|
data = createFrame(options.data);
|
||||||
data.contextPath = appendContextPath(options.data.contextPath, options.ids[0]);
|
data.contextPath = appendContextPath(
|
||||||
|
options.data.contextPath,
|
||||||
|
options.ids[0]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fn(context, {
|
return fn(context, {
|
||||||
|
|||||||
@@ -22,9 +22,13 @@ let logger = {
|
|||||||
log: function(level, ...message) {
|
log: function(level, ...message) {
|
||||||
level = logger.lookupLevel(level);
|
level = logger.lookupLevel(level);
|
||||||
|
|
||||||
if (typeof console !== 'undefined' && logger.lookupLevel(logger.level) <= level) {
|
if (
|
||||||
|
typeof console !== 'undefined' &&
|
||||||
|
logger.lookupLevel(logger.level) <= level
|
||||||
|
) {
|
||||||
let method = logger.methodMap[level];
|
let method = logger.methodMap[level];
|
||||||
if (!console[method]) { // eslint-disable-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
if (!console[method]) {
|
||||||
method = 'log';
|
method = 'log';
|
||||||
}
|
}
|
||||||
console[method](...message); // eslint-disable-line no-console
|
console[method](...message); // eslint-disable-line no-console
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/* global window */
|
|
||||||
export default function(Handlebars) {
|
export default function(Handlebars) {
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
let root = typeof global !== 'undefined' ? global : window,
|
let root = typeof global !== 'undefined' ? global : window,
|
||||||
|
|||||||
+137
-33
@@ -1,30 +1,47 @@
|
|||||||
import * as Utils from './utils';
|
import * as Utils from './utils';
|
||||||
import Exception from './exception';
|
import Exception from './exception';
|
||||||
import {COMPILER_REVISION, createFrame, LAST_COMPATIBLE_COMPILER_REVISION, REVISION_CHANGES} from './base';
|
import {
|
||||||
|
COMPILER_REVISION,
|
||||||
|
createFrame,
|
||||||
|
LAST_COMPATIBLE_COMPILER_REVISION,
|
||||||
|
REVISION_CHANGES
|
||||||
|
} from './base';
|
||||||
import { moveHelperToHooks } from './helpers';
|
import { moveHelperToHooks } from './helpers';
|
||||||
|
|
||||||
export function checkRevision(compilerInfo) {
|
export function checkRevision(compilerInfo) {
|
||||||
const compilerRevision = compilerInfo && compilerInfo[0] || 1,
|
const compilerRevision = (compilerInfo && compilerInfo[0]) || 1,
|
||||||
currentRevision = COMPILER_REVISION;
|
currentRevision = COMPILER_REVISION;
|
||||||
|
|
||||||
if (compilerRevision >= LAST_COMPATIBLE_COMPILER_REVISION && compilerRevision <= COMPILER_REVISION) {
|
if (
|
||||||
|
compilerRevision >= LAST_COMPATIBLE_COMPILER_REVISION &&
|
||||||
|
compilerRevision <= COMPILER_REVISION
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compilerRevision < LAST_COMPATIBLE_COMPILER_REVISION) {
|
if (compilerRevision < LAST_COMPATIBLE_COMPILER_REVISION) {
|
||||||
const runtimeVersions = REVISION_CHANGES[currentRevision],
|
const runtimeVersions = REVISION_CHANGES[currentRevision],
|
||||||
compilerVersions = REVISION_CHANGES[compilerRevision];
|
compilerVersions = REVISION_CHANGES[compilerRevision];
|
||||||
throw new Exception('Template was precompiled with an older version of Handlebars than the current runtime. ' +
|
throw new Exception(
|
||||||
'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
|
'Template was precompiled with an older version of Handlebars than the current runtime. ' +
|
||||||
|
'Please update your precompiler to a newer version (' +
|
||||||
|
runtimeVersions +
|
||||||
|
') or downgrade your runtime to an older version (' +
|
||||||
|
compilerVersions +
|
||||||
|
').'
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// Use the embedded version info since the runtime doesn't know about this revision yet
|
// Use the embedded version info since the runtime doesn't know about this revision yet
|
||||||
throw new Exception('Template was precompiled with a newer version of Handlebars than the current runtime. ' +
|
throw new Exception(
|
||||||
'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
|
'Template was precompiled with a newer version of Handlebars than the current runtime. ' +
|
||||||
|
'Please update your runtime to a newer version (' +
|
||||||
|
compilerInfo[1] +
|
||||||
|
').'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function template(templateSpec, env) {
|
export function template(templateSpec, env) {
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
if (!env) {
|
if (!env) {
|
||||||
throw new Exception('No environment passed to template');
|
throw new Exception('No environment passed to template');
|
||||||
@@ -40,7 +57,8 @@ export function template(templateSpec, env) {
|
|||||||
env.VM.checkRevision(templateSpec.compiler);
|
env.VM.checkRevision(templateSpec.compiler);
|
||||||
|
|
||||||
// backwards compatibility for precompiled templates with compiler-version 7 (<4.3.0)
|
// backwards compatibility for precompiled templates with compiler-version 7 (<4.3.0)
|
||||||
const templateWasPrecompiledWithCompilerV7 = templateSpec.compiler && templateSpec.compiler[0] === 7;
|
const templateWasPrecompiledWithCompilerV7 =
|
||||||
|
templateSpec.compiler && templateSpec.compiler[0] === 7;
|
||||||
|
|
||||||
function invokePartialWrapper(partial, context, options) {
|
function invokePartialWrapper(partial, context, options) {
|
||||||
if (options.hash) {
|
if (options.hash) {
|
||||||
@@ -53,10 +71,19 @@ export function template(templateSpec, env) {
|
|||||||
|
|
||||||
let optionsWithHooks = Utils.extend({}, options, { hooks: this.hooks });
|
let optionsWithHooks = Utils.extend({}, options, { hooks: this.hooks });
|
||||||
|
|
||||||
let result = env.VM.invokePartial.call(this, partial, context, optionsWithHooks);
|
let result = env.VM.invokePartial.call(
|
||||||
|
this,
|
||||||
|
partial,
|
||||||
|
context,
|
||||||
|
optionsWithHooks
|
||||||
|
);
|
||||||
|
|
||||||
if (result == null && env.compile) {
|
if (result == null && env.compile) {
|
||||||
options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env);
|
options.partials[options.name] = env.compile(
|
||||||
|
partial,
|
||||||
|
templateSpec.compilerOptions,
|
||||||
|
env
|
||||||
|
);
|
||||||
result = options.partials[options.name](context, optionsWithHooks);
|
result = options.partials[options.name](context, optionsWithHooks);
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -73,7 +100,11 @@ export function template(templateSpec, env) {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
throw new Exception('The partial ' + options.name + ' could not be compiled when running in runtime-only mode');
|
throw new Exception(
|
||||||
|
'The partial ' +
|
||||||
|
options.name +
|
||||||
|
' could not be compiled when running in runtime-only mode'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +112,9 @@ export function template(templateSpec, env) {
|
|||||||
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, { loc: loc });
|
throw new Exception('"' + name + '" not defined in ' + obj, {
|
||||||
|
loc: loc
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return obj[name];
|
return obj[name];
|
||||||
},
|
},
|
||||||
@@ -111,7 +144,15 @@ export function template(templateSpec, env) {
|
|||||||
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) {
|
||||||
programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths);
|
programWrapper = wrapProgram(
|
||||||
|
this,
|
||||||
|
i,
|
||||||
|
fn,
|
||||||
|
data,
|
||||||
|
declaredBlockParams,
|
||||||
|
blockParams,
|
||||||
|
depths
|
||||||
|
);
|
||||||
} else if (!programWrapper) {
|
} else if (!programWrapper) {
|
||||||
programWrapper = this.programs[i] = wrapProgram(this, i, fn);
|
programWrapper = this.programs[i] = wrapProgram(this, i, fn);
|
||||||
}
|
}
|
||||||
@@ -127,7 +168,7 @@ export function template(templateSpec, env) {
|
|||||||
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) {
|
||||||
obj = Utils.extend({}, common, param);
|
obj = Utils.extend({}, common, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,16 +192,37 @@ export function template(templateSpec, env) {
|
|||||||
blockParams = templateSpec.useBlockParams ? [] : undefined;
|
blockParams = templateSpec.useBlockParams ? [] : undefined;
|
||||||
if (templateSpec.useDepths) {
|
if (templateSpec.useDepths) {
|
||||||
if (options.depths) {
|
if (options.depths) {
|
||||||
depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths;
|
depths =
|
||||||
|
context != options.depths[0]
|
||||||
|
? [context].concat(options.depths)
|
||||||
|
: options.depths;
|
||||||
} else {
|
} else {
|
||||||
depths = [context];
|
depths = [context];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function main(context /*, options*/) {
|
function main(context /*, options*/) {
|
||||||
return '' + templateSpec.main(container, context, container.helpers, container.partials, data, blockParams, depths);
|
return (
|
||||||
|
'' +
|
||||||
|
templateSpec.main(
|
||||||
|
container,
|
||||||
|
context,
|
||||||
|
container.helpers,
|
||||||
|
container.partials,
|
||||||
|
data,
|
||||||
|
blockParams,
|
||||||
|
depths
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
main = executeDecorators(templateSpec.main, main, container, options.depths || [], data, blockParams);
|
main = executeDecorators(
|
||||||
|
templateSpec.main,
|
||||||
|
main,
|
||||||
|
container,
|
||||||
|
options.depths || [],
|
||||||
|
data,
|
||||||
|
blockParams
|
||||||
|
);
|
||||||
return main(context, options);
|
return main(context, options);
|
||||||
}
|
}
|
||||||
ret.isTop = true;
|
ret.isTop = true;
|
||||||
@@ -171,25 +233,32 @@ export function template(templateSpec, env) {
|
|||||||
|
|
||||||
if (templateSpec.usePartial) {
|
if (templateSpec.usePartial) {
|
||||||
// Use mergeIfNeeded here to prevent compiling global partials multiple times
|
// Use mergeIfNeeded here to prevent compiling global partials multiple times
|
||||||
container.partials = container.mergeIfNeeded(options.partials, env.partials);
|
container.partials = container.mergeIfNeeded(
|
||||||
|
options.partials,
|
||||||
|
env.partials
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (templateSpec.usePartial || templateSpec.useDecorators) {
|
if (templateSpec.usePartial || templateSpec.useDecorators) {
|
||||||
container.decorators = Utils.extend({}, env.decorators, options.decorators);
|
container.decorators = Utils.extend(
|
||||||
|
{},
|
||||||
|
env.decorators,
|
||||||
|
options.decorators
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
container.hooks = {};
|
container.hooks = {};
|
||||||
|
|
||||||
let keepHelperInHelpers = options.allowCallsToHelperMissing || templateWasPrecompiledWithCompilerV7;
|
let keepHelperInHelpers =
|
||||||
|
options.allowCallsToHelperMissing ||
|
||||||
|
templateWasPrecompiledWithCompilerV7;
|
||||||
moveHelperToHooks(container, 'helperMissing', keepHelperInHelpers);
|
moveHelperToHooks(container, 'helperMissing', keepHelperInHelpers);
|
||||||
moveHelperToHooks(container, 'blockHelperMissing', keepHelperInHelpers);
|
moveHelperToHooks(container, 'blockHelperMissing', keepHelperInHelpers);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
container.helpers = options.helpers;
|
container.helpers = options.helpers;
|
||||||
container.partials = options.partials;
|
container.partials = options.partials;
|
||||||
container.decorators = options.decorators;
|
container.decorators = options.decorators;
|
||||||
container.hooks = options.hooks;
|
container.hooks = options.hooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ret._child = function(i, data, blockParams, depths) {
|
ret._child = function(i, data, blockParams, depths) {
|
||||||
@@ -200,24 +269,47 @@ export function template(templateSpec, env) {
|
|||||||
throw new Exception('must pass parent depths');
|
throw new Exception('must pass parent depths');
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths);
|
return wrapProgram(
|
||||||
|
container,
|
||||||
|
i,
|
||||||
|
templateSpec[i],
|
||||||
|
data,
|
||||||
|
0,
|
||||||
|
blockParams,
|
||||||
|
depths
|
||||||
|
);
|
||||||
};
|
};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
|
export function wrapProgram(
|
||||||
|
container,
|
||||||
|
i,
|
||||||
|
fn,
|
||||||
|
data,
|
||||||
|
declaredBlockParams,
|
||||||
|
blockParams,
|
||||||
|
depths
|
||||||
|
) {
|
||||||
function prog(context, options = {}) {
|
function prog(context, options = {}) {
|
||||||
let currentDepths = depths;
|
let currentDepths = depths;
|
||||||
if (depths && context != depths[0] && !(context === container.nullContext && depths[0] === null)) {
|
if (
|
||||||
|
depths &&
|
||||||
|
context != depths[0] &&
|
||||||
|
!(context === container.nullContext && depths[0] === null)
|
||||||
|
) {
|
||||||
currentDepths = [context].concat(depths);
|
currentDepths = [context].concat(depths);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fn(container,
|
return fn(
|
||||||
|
container,
|
||||||
context,
|
context,
|
||||||
container.helpers, container.partials,
|
container.helpers,
|
||||||
|
container.partials,
|
||||||
options.data || data,
|
options.data || data,
|
||||||
blockParams && [options.blockParams].concat(blockParams),
|
blockParams && [options.blockParams].concat(blockParams),
|
||||||
currentDepths);
|
currentDepths
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
prog = executeDecorators(fn, prog, container, depths, data, blockParams);
|
prog = executeDecorators(fn, prog, container, depths, data, blockParams);
|
||||||
@@ -259,8 +351,10 @@ export function invokePartial(partial, context, options) {
|
|||||||
options.data = createFrame(options.data);
|
options.data = createFrame(options.data);
|
||||||
// Wrapper function to get access to currentPartialBlock from the closure
|
// Wrapper function to get access to currentPartialBlock from the closure
|
||||||
let fn = options.fn;
|
let fn = options.fn;
|
||||||
partialBlock = options.data['partial-block'] = function partialBlockWrapper(context, options = {}) {
|
partialBlock = options.data['partial-block'] = function partialBlockWrapper(
|
||||||
|
context,
|
||||||
|
options = {}
|
||||||
|
) {
|
||||||
// Restore the partial-block from the closure for the execution of the block
|
// Restore the partial-block from the closure for the execution of the block
|
||||||
// i.e. the part inside the block of the partial call.
|
// i.e. the part inside the block of the partial call.
|
||||||
options.data = createFrame(options.data);
|
options.data = createFrame(options.data);
|
||||||
@@ -283,7 +377,9 @@ export function invokePartial(partial, context, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function noop() { return ''; }
|
export function noop() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
function initData(context, data) {
|
function initData(context, data) {
|
||||||
if (!data || !('root' in data)) {
|
if (!data || !('root' in data)) {
|
||||||
@@ -296,7 +392,15 @@ function initData(context, data) {
|
|||||||
function executeDecorators(fn, prog, container, depths, data, blockParams) {
|
function executeDecorators(fn, prog, container, depths, data, blockParams) {
|
||||||
if (fn.decorator) {
|
if (fn.decorator) {
|
||||||
let props = {};
|
let props = {};
|
||||||
prog = fn.decorator(prog, props, container, depths && depths[0], data, blockParams, depths);
|
prog = fn.decorator(
|
||||||
|
prog,
|
||||||
|
props,
|
||||||
|
container,
|
||||||
|
depths && depths[0],
|
||||||
|
data,
|
||||||
|
blockParams,
|
||||||
|
depths
|
||||||
|
);
|
||||||
Utils.extend(prog, props);
|
Utils.extend(prog, props);
|
||||||
}
|
}
|
||||||
return prog;
|
return prog;
|
||||||
|
|||||||
+13
-6
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
const escape = {
|
const escape = {
|
||||||
'&': '&',
|
'&': '&',
|
||||||
'<': '<',
|
'<': '<',
|
||||||
@@ -40,15 +39,22 @@ let isFunction = function(value) {
|
|||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
if (isFunction(/x/)) {
|
if (isFunction(/x/)) {
|
||||||
isFunction = function(value) {
|
isFunction = function(value) {
|
||||||
return typeof value === 'function' && toString.call(value) === '[object Function]';
|
return (
|
||||||
|
typeof value === 'function' &&
|
||||||
|
toString.call(value) === '[object Function]'
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export { isFunction };
|
export { isFunction };
|
||||||
/* eslint-enable func-style */
|
/* eslint-enable func-style */
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
export const isArray = Array.isArray || function(value) {
|
export const isArray =
|
||||||
return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false;
|
Array.isArray ||
|
||||||
|
function(value) {
|
||||||
|
return value && typeof value === 'object'
|
||||||
|
? toString.call(value) === '[object Array]'
|
||||||
|
: false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Older IE versions do not directly support indexOf so we must implement our own, sadly.
|
// Older IE versions do not directly support indexOf so we must implement our own, sadly.
|
||||||
@@ -61,7 +67,6 @@ export function indexOf(array, value) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function escapeExpression(string) {
|
export function escapeExpression(string) {
|
||||||
if (typeof string !== 'string') {
|
if (typeof string !== 'string') {
|
||||||
// don't escape SafeStrings, since they're already safe
|
// don't escape SafeStrings, since they're already safe
|
||||||
@@ -79,7 +84,9 @@ export function escapeExpression(string) {
|
|||||||
string = '' + string;
|
string = '' + string;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!possible.test(string)) { return string; }
|
if (!possible.test(string)) {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
return string.replace(badChars, escapeChar);
|
return string.replace(badChars, escapeChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+62
-20
@@ -5,7 +5,6 @@ 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) {
|
||||||
@@ -27,12 +26,17 @@ function loadStrings(opts, callback) {
|
|||||||
let strings = arrayCast(opts.string),
|
let strings = arrayCast(opts.string),
|
||||||
names = arrayCast(opts.name);
|
names = arrayCast(opts.name);
|
||||||
|
|
||||||
if (names.length !== strings.length
|
if (names.length !== strings.length && strings.length > 1) {
|
||||||
&& strings.length > 1) {
|
return callback(
|
||||||
return callback(new Handlebars.Exception('Number of names did not match the number of string inputs'));
|
new Handlebars.Exception(
|
||||||
|
'Number of names did not match the number of string inputs'
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Async.map(strings, function(string, callback) {
|
Async.map(
|
||||||
|
strings,
|
||||||
|
function(string, callback) {
|
||||||
if (string !== '-') {
|
if (string !== '-') {
|
||||||
callback(undefined, string);
|
callback(undefined, string);
|
||||||
} else {
|
} else {
|
||||||
@@ -55,22 +59,32 @@ function loadStrings(opts, callback) {
|
|||||||
source: string
|
source: string
|
||||||
}));
|
}));
|
||||||
callback(err, strings);
|
callback(err, strings);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFiles(opts, callback) {
|
function loadFiles(opts, callback) {
|
||||||
// Build file extension pattern
|
// Build file extension pattern
|
||||||
let extension = (opts.extension || 'handlebars').replace(/[\\^$*+?.():=!|{}\-[\]]/g, function(arg) { return '\\' + arg; });
|
let extension = (opts.extension || 'handlebars').replace(
|
||||||
|
/[\\^$*+?.():=!|{}\-[\]]/g,
|
||||||
|
function(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(() => queue.length, function(callback) {
|
Async.whilst(
|
||||||
|
() => queue.length,
|
||||||
|
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(new Handlebars.Exception(`Unable to open template file "${path}"`));
|
return callback(
|
||||||
|
new Handlebars.Exception(`Unable to open template file "${path}"`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat.isDirectory()) {
|
if (stat.isDirectory()) {
|
||||||
@@ -84,7 +98,10 @@ function loadFiles(opts, callback) {
|
|||||||
children.forEach(function(file) {
|
children.forEach(function(file) {
|
||||||
let childPath = path + '/' + file;
|
let childPath = path + '/' + file;
|
||||||
|
|
||||||
if (extension.test(childPath) || fs.statSync(childPath).isDirectory()) {
|
if (
|
||||||
|
extension.test(childPath) ||
|
||||||
|
fs.statSync(childPath).isDirectory()
|
||||||
|
) {
|
||||||
queue.push({ template: childPath, root: root || path });
|
queue.push({ template: childPath, root: root || path });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -128,7 +145,8 @@ function loadFiles(opts, callback) {
|
|||||||
} else {
|
} else {
|
||||||
callback(undefined, ret);
|
callback(undefined, ret);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.cli = function(opts) {
|
module.exports.cli = function(opts) {
|
||||||
@@ -138,7 +156,9 @@ module.exports.cli = function(opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!opts.templates.length && !opts.hasDirectory) {
|
if (!opts.templates.length && !opts.hasDirectory) {
|
||||||
throw new Handlebars.Exception('Must define at least one template or directory.');
|
throw new Handlebars.Exception(
|
||||||
|
'Must define at least one template or directory.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.simple && opts.min) {
|
if (opts.simple && opts.min) {
|
||||||
@@ -147,12 +167,18 @@ module.exports.cli = function(opts) {
|
|||||||
|
|
||||||
const multiple = opts.templates.length !== 1 || opts.hasDirectory;
|
const multiple = opts.templates.length !== 1 || opts.hasDirectory;
|
||||||
if (opts.simple && multiple) {
|
if (opts.simple && multiple) {
|
||||||
throw new Handlebars.Exception('Unable to output multiple templates in simple mode');
|
throw new Handlebars.Exception(
|
||||||
|
'Unable to output multiple templates in simple mode'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force simple mode if we have only one template and it's unnamed.
|
// Force simple mode if we have only one template and it's unnamed.
|
||||||
if (!opts.amd && !opts.commonjs && opts.templates.length === 1
|
if (
|
||||||
&& !opts.templates[0].name) {
|
!opts.amd &&
|
||||||
|
!opts.commonjs &&
|
||||||
|
opts.templates.length === 1 &&
|
||||||
|
!opts.templates[0].name
|
||||||
|
) {
|
||||||
opts.simple = true;
|
opts.simple = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +198,11 @@ module.exports.cli = function(opts) {
|
|||||||
let output = new SourceNode();
|
let output = new SourceNode();
|
||||||
if (!opts.simple) {
|
if (!opts.simple) {
|
||||||
if (opts.amd) {
|
if (opts.amd) {
|
||||||
output.add('define([\'' + opts.handlebarPath + 'handlebars.runtime\'], function(Handlebars) {\n Handlebars = Handlebars["default"];');
|
output.add(
|
||||||
|
"define(['" +
|
||||||
|
opts.handlebarPath +
|
||||||
|
'handlebars.runtime\'], function(Handlebars) {\n Handlebars = Handlebars["default"];'
|
||||||
|
);
|
||||||
} else if (opts.commonjs) {
|
} else if (opts.commonjs) {
|
||||||
output.add('var Handlebars = require("' + opts.commonjs + '");');
|
output.add('var Handlebars = require("' + opts.commonjs + '");');
|
||||||
} else {
|
} else {
|
||||||
@@ -206,7 +236,10 @@ module.exports.cli = function(opts) {
|
|||||||
// If we are generating a source map, we have to reconstruct the SourceNode object
|
// If we are generating a source map, we have to reconstruct the SourceNode object
|
||||||
if (opts.map) {
|
if (opts.map) {
|
||||||
let consumer = new SourceMapConsumer(precompiled.map);
|
let consumer = new SourceMapConsumer(precompiled.map);
|
||||||
precompiled = SourceNode.fromStringWithSourceMap(precompiled.code, consumer);
|
precompiled = SourceNode.fromStringWithSourceMap(
|
||||||
|
precompiled.code,
|
||||||
|
consumer
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.simple) {
|
if (opts.simple) {
|
||||||
@@ -219,7 +252,14 @@ module.exports.cli = function(opts) {
|
|||||||
if (opts.amd && !multiple) {
|
if (opts.amd && !multiple) {
|
||||||
output.add('return ');
|
output.add('return ');
|
||||||
}
|
}
|
||||||
output.add([objectName, '[\'', template.name, '\'] = template(', precompiled, ');\n']);
|
output.add([
|
||||||
|
objectName,
|
||||||
|
"['",
|
||||||
|
template.name,
|
||||||
|
"'] = template(",
|
||||||
|
precompiled,
|
||||||
|
');\n'
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -286,7 +326,9 @@ function minify(output, sourceMapFile) {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
// it does not exist!
|
// it does not exist!
|
||||||
console.error('Code minimization is disabled due to missing uglify-js dependency');
|
console.error(
|
||||||
|
'Code minimization is disabled due to missing uglify-js dependency'
|
||||||
|
);
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
return require('uglify-js').minify(output.code, {
|
return require('uglify-js').minify(output.code, {
|
||||||
|
|||||||
+115
-35
@@ -7,23 +7,69 @@ describe('ast', function() {
|
|||||||
|
|
||||||
describe('BlockStatement', function() {
|
describe('BlockStatement', function() {
|
||||||
it('should throw on mustache mismatch', function() {
|
it('should throw on mustache mismatch', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
handlebarsEnv.parse('\n {{#foo}}{{/bar}}');
|
handlebarsEnv.parse('\n {{#foo}}{{/bar}}');
|
||||||
}, Handlebars.Exception, "foo doesn't match bar - 2:5");
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
"foo doesn't match bar - 2:5"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
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(AST.helpers.helperExpression({type: 'MustacheStatement', params: [], hash: undefined}), false);
|
equals(
|
||||||
equals(AST.helpers.helperExpression({type: 'MustacheStatement', params: [1], hash: undefined}), true);
|
AST.helpers.helperExpression({
|
||||||
equals(AST.helpers.helperExpression({type: 'MustacheStatement', params: [], hash: {}}), true);
|
type: 'MustacheStatement',
|
||||||
|
params: [],
|
||||||
|
hash: undefined
|
||||||
|
}),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
AST.helpers.helperExpression({
|
||||||
|
type: 'MustacheStatement',
|
||||||
|
params: [1],
|
||||||
|
hash: undefined
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
AST.helpers.helperExpression({
|
||||||
|
type: 'MustacheStatement',
|
||||||
|
params: [],
|
||||||
|
hash: {}
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should handle block statements', function() {
|
it('should handle block statements', function() {
|
||||||
equals(AST.helpers.helperExpression({type: 'BlockStatement', params: [], hash: undefined}), false);
|
equals(
|
||||||
equals(AST.helpers.helperExpression({type: 'BlockStatement', params: [1], hash: undefined}), true);
|
AST.helpers.helperExpression({
|
||||||
equals(AST.helpers.helperExpression({type: 'BlockStatement', params: [], hash: {}}), true);
|
type: 'BlockStatement',
|
||||||
|
params: [],
|
||||||
|
hash: undefined
|
||||||
|
}),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
AST.helpers.helperExpression({
|
||||||
|
type: 'BlockStatement',
|
||||||
|
params: [1],
|
||||||
|
hash: undefined
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
AST.helpers.helperExpression({
|
||||||
|
type: 'BlockStatement',
|
||||||
|
params: [],
|
||||||
|
hash: {}
|
||||||
|
}),
|
||||||
|
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);
|
||||||
@@ -31,16 +77,28 @@ describe('ast', function() {
|
|||||||
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(AST.helpers.helperExpression({type: 'PartialStatement'}), false);
|
equals(
|
||||||
equals(AST.helpers.helperExpression({type: 'ContentStatement'}), false);
|
AST.helpers.helperExpression({ type: 'PartialStatement' }),
|
||||||
equals(AST.helpers.helperExpression({type: 'CommentStatement'}), false);
|
false
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
AST.helpers.helperExpression({ type: 'ContentStatement' }),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
AST.helpers.helperExpression({ type: 'CommentStatement' }),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
equals(AST.helpers.helperExpression({ type: 'PathExpression' }), false);
|
equals(AST.helpers.helperExpression({ type: 'PathExpression' }), false);
|
||||||
|
|
||||||
equals(AST.helpers.helperExpression({ type: 'StringLiteral' }), false);
|
equals(AST.helpers.helperExpression({ type: 'StringLiteral' }), false);
|
||||||
equals(AST.helpers.helperExpression({ type: 'NumberLiteral' }), false);
|
equals(AST.helpers.helperExpression({ type: 'NumberLiteral' }), false);
|
||||||
equals(AST.helpers.helperExpression({ type: 'BooleanLiteral' }), false);
|
equals(AST.helpers.helperExpression({ type: 'BooleanLiteral' }), false);
|
||||||
equals(AST.helpers.helperExpression({type: 'UndefinedLiteral'}), false);
|
equals(
|
||||||
|
AST.helpers.helperExpression({ type: 'UndefinedLiteral' }),
|
||||||
|
false
|
||||||
|
);
|
||||||
equals(AST.helpers.helperExpression({ type: 'NullLiteral' }), false);
|
equals(AST.helpers.helperExpression({ type: 'NullLiteral' }), false);
|
||||||
|
|
||||||
equals(AST.helpers.helperExpression({ type: 'Hash' }), false);
|
equals(AST.helpers.helperExpression({ type: 'Hash' }), false);
|
||||||
@@ -61,17 +119,18 @@ 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}}'); // 11
|
'{{/open}}'
|
||||||
|
); // 11
|
||||||
/* eslint-enable no-multi-spaces */
|
/* eslint-enable no-multi-spaces */
|
||||||
body = ast.body;
|
body = ast.body;
|
||||||
|
|
||||||
@@ -149,7 +208,9 @@ describe('ast', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('block statements', function() {
|
it('block statements', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing(' {{# comment~}} \nfoo\n {{~/comment}}');
|
var ast = Handlebars.parseWithoutProcessing(
|
||||||
|
' {{# comment~}} \nfoo\n {{~/comment}}'
|
||||||
|
);
|
||||||
|
|
||||||
equals(ast.body[0].value, ' ');
|
equals(ast.body[0].value, ' ');
|
||||||
equals(ast.body[1].program.body[0].value, ' \nfoo\n ');
|
equals(ast.body[1].program.body[0].value, ' \nfoo\n ');
|
||||||
@@ -167,7 +228,9 @@ describe('ast', function() {
|
|||||||
});
|
});
|
||||||
describe('blocks - parseWithoutProcessing', function() {
|
describe('blocks - parseWithoutProcessing', function() {
|
||||||
it('block mustaches', function() {
|
it('block mustaches', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing(' {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '),
|
var ast = Handlebars.parseWithoutProcessing(
|
||||||
|
' {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '
|
||||||
|
),
|
||||||
block = ast.body[1];
|
block = ast.body[1];
|
||||||
|
|
||||||
equals(ast.body[0].value, ' ');
|
equals(ast.body[0].value, ' ');
|
||||||
@@ -178,13 +241,17 @@ describe('ast', function() {
|
|||||||
equals(ast.body[2].value, ' ');
|
equals(ast.body[2].value, ' ');
|
||||||
});
|
});
|
||||||
it('initial block mustaches', function() {
|
it('initial block mustaches', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing('{{# comment}} \nfoo\n {{/comment}}'),
|
var ast = Handlebars.parseWithoutProcessing(
|
||||||
|
'{{# comment}} \nfoo\n {{/comment}}'
|
||||||
|
),
|
||||||
block = ast.body[0];
|
block = ast.body[0];
|
||||||
|
|
||||||
equals(block.program.body[0].value, ' \nfoo\n ');
|
equals(block.program.body[0].value, ' \nfoo\n ');
|
||||||
});
|
});
|
||||||
it('mustaches with children', function() {
|
it('mustaches with children', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing('{{# comment}} \n{{foo}}\n {{/comment}}'),
|
var ast = Handlebars.parseWithoutProcessing(
|
||||||
|
'{{# comment}} \n{{foo}}\n {{/comment}}'
|
||||||
|
),
|
||||||
block = ast.body[0];
|
block = ast.body[0];
|
||||||
|
|
||||||
equals(block.program.body[0].value, ' \n');
|
equals(block.program.body[0].value, ' \n');
|
||||||
@@ -192,7 +259,9 @@ describe('ast', function() {
|
|||||||
equals(block.program.body[2].value, '\n ');
|
equals(block.program.body[2].value, '\n ');
|
||||||
});
|
});
|
||||||
it('nested block mustaches', function() {
|
it('nested block mustaches', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing('{{#foo}} \n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} \n{{/foo}}'),
|
var ast = Handlebars.parseWithoutProcessing(
|
||||||
|
'{{#foo}} \n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} \n{{/foo}}'
|
||||||
|
),
|
||||||
body = ast.body[0].program.body,
|
body = ast.body[0].program.body,
|
||||||
block = body[1];
|
block = body[1];
|
||||||
|
|
||||||
@@ -202,7 +271,9 @@ describe('ast', function() {
|
|||||||
equals(block.inverse.body[0].value, ' \n bar \n ');
|
equals(block.inverse.body[0].value, ' \n bar \n ');
|
||||||
});
|
});
|
||||||
it('column 0 block mustaches', function() {
|
it('column 0 block mustaches', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing('test\n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '),
|
var ast = Handlebars.parseWithoutProcessing(
|
||||||
|
'test\n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '
|
||||||
|
),
|
||||||
block = ast.body[1];
|
block = ast.body[1];
|
||||||
|
|
||||||
equals(ast.body[0].omit, undefined);
|
equals(ast.body[0].omit, undefined);
|
||||||
@@ -215,7 +286,9 @@ describe('ast', function() {
|
|||||||
});
|
});
|
||||||
describe('blocks', function() {
|
describe('blocks', function() {
|
||||||
it('marks block mustaches as standalone', function() {
|
it('marks block mustaches as standalone', function() {
|
||||||
var ast = Handlebars.parse(' {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '),
|
var ast = Handlebars.parse(
|
||||||
|
' {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '
|
||||||
|
),
|
||||||
block = ast.body[1];
|
block = ast.body[1];
|
||||||
|
|
||||||
equals(ast.body[0].value, '');
|
equals(ast.body[0].value, '');
|
||||||
@@ -240,7 +313,9 @@ describe('ast', function() {
|
|||||||
equals(block.program.body[2].value, '\n');
|
equals(block.program.body[2].value, '\n');
|
||||||
});
|
});
|
||||||
it('marks nested block mustaches as standalone', function() {
|
it('marks nested block mustaches as standalone', function() {
|
||||||
var ast = Handlebars.parse('{{#foo}} \n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} \n{{/foo}}'),
|
var ast = Handlebars.parse(
|
||||||
|
'{{#foo}} \n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} \n{{/foo}}'
|
||||||
|
),
|
||||||
body = ast.body[0].program.body,
|
body = ast.body[0].program.body,
|
||||||
block = body[1];
|
block = body[1];
|
||||||
|
|
||||||
@@ -252,7 +327,9 @@ describe('ast', function() {
|
|||||||
equals(body[0].value, '');
|
equals(body[0].value, '');
|
||||||
});
|
});
|
||||||
it('does not mark nested block mustaches as standalone', function() {
|
it('does not mark nested block mustaches as standalone', function() {
|
||||||
var ast = Handlebars.parse('{{#foo}} {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} {{/foo}}'),
|
var ast = Handlebars.parse(
|
||||||
|
'{{#foo}} {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} {{/foo}}'
|
||||||
|
),
|
||||||
body = ast.body[0].program.body,
|
body = ast.body[0].program.body,
|
||||||
block = body[1];
|
block = body[1];
|
||||||
|
|
||||||
@@ -264,7 +341,9 @@ describe('ast', function() {
|
|||||||
equals(body[0].omit, undefined);
|
equals(body[0].omit, undefined);
|
||||||
});
|
});
|
||||||
it('does not mark nested initial block mustaches as standalone', function() {
|
it('does not mark nested initial block mustaches as standalone', function() {
|
||||||
var ast = Handlebars.parse('{{#foo}}{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}}{{/foo}}'),
|
var ast = Handlebars.parse(
|
||||||
|
'{{#foo}}{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}}{{/foo}}'
|
||||||
|
),
|
||||||
body = ast.body[0].program.body,
|
body = ast.body[0].program.body,
|
||||||
block = body[0];
|
block = body[0];
|
||||||
|
|
||||||
@@ -275,7 +354,9 @@ describe('ast', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('marks column 0 block mustaches as standalone', function() {
|
it('marks column 0 block mustaches as standalone', function() {
|
||||||
var ast = Handlebars.parse('test\n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '),
|
var ast = Handlebars.parse(
|
||||||
|
'test\n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '
|
||||||
|
),
|
||||||
block = ast.body[1];
|
block = ast.body[1];
|
||||||
|
|
||||||
equals(ast.body[0].omit, undefined);
|
equals(ast.body[0].omit, undefined);
|
||||||
@@ -348,4 +429,3 @@ describe('ast', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+418
-115
@@ -18,8 +18,12 @@ describe('basic context', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('compiling with a basic context', function() {
|
it('compiling with a basic context', function() {
|
||||||
shouldCompileTo('Goodbye\n{{cruel}}\n{{world}}!', {cruel: 'cruel', world: 'world'}, 'Goodbye\ncruel\nworld!',
|
shouldCompileTo(
|
||||||
'It works if all the required keys are provided');
|
'Goodbye\n{{cruel}}\n{{world}}!',
|
||||||
|
{ cruel: 'cruel', world: 'world' },
|
||||||
|
'Goodbye\ncruel\nworld!',
|
||||||
|
'It works if all the required keys are provided'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('compiling with a string context', function() {
|
it('compiling with a string context', function() {
|
||||||
@@ -27,15 +31,26 @@ describe('basic context', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('compiling with an undefined context', function() {
|
it('compiling with an undefined context', function() {
|
||||||
shouldCompileTo('Goodbye\n{{cruel}}\n{{world.bar}}!', undefined, 'Goodbye\n\n!');
|
shouldCompileTo(
|
||||||
|
'Goodbye\n{{cruel}}\n{{world.bar}}!',
|
||||||
|
undefined,
|
||||||
|
'Goodbye\n\n!'
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileTo('{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}', undefined, 'Goodbye');
|
shouldCompileTo(
|
||||||
|
'{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}',
|
||||||
|
undefined,
|
||||||
|
'Goodbye'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('comments', function() {
|
it('comments', function() {
|
||||||
shouldCompileTo('{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!',
|
shouldCompileTo(
|
||||||
{cruel: 'cruel', world: 'world'}, 'Goodbye\ncruel\nworld!',
|
'{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!',
|
||||||
'comments are ignored');
|
{ cruel: 'cruel', world: 'world' },
|
||||||
|
'Goodbye\ncruel\nworld!',
|
||||||
|
'comments are ignored'
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileTo(' {{~! comment ~}} blah', {}, 'blah');
|
shouldCompileTo(' {{~! comment ~}} blah', {}, 'blah');
|
||||||
shouldCompileTo(' {{~!-- long-comment --~}} blah', {}, 'blah');
|
shouldCompileTo(' {{~!-- long-comment --~}} blah', {}, 'blah');
|
||||||
@@ -47,52 +62,91 @@ describe('basic context', function() {
|
|||||||
|
|
||||||
it('boolean', function() {
|
it('boolean', function() {
|
||||||
var string = '{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!';
|
var string = '{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!';
|
||||||
shouldCompileTo(string, {goodbye: true, world: 'world'}, 'GOODBYE cruel world!',
|
shouldCompileTo(
|
||||||
'booleans show the contents when true');
|
string,
|
||||||
|
{ goodbye: true, world: 'world' },
|
||||||
|
'GOODBYE cruel world!',
|
||||||
|
'booleans show the contents when true'
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileTo(string, {goodbye: false, world: 'world'}, 'cruel world!',
|
shouldCompileTo(
|
||||||
'booleans do not show the contents when false');
|
string,
|
||||||
|
{ goodbye: false, world: 'world' },
|
||||||
|
'cruel world!',
|
||||||
|
'booleans do not show the contents when false'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('zeros', function() {
|
it('zeros', function() {
|
||||||
shouldCompileTo('num1: {{num1}}, num2: {{num2}}', {num1: 42, num2: 0},
|
shouldCompileTo(
|
||||||
'num1: 42, num2: 0');
|
'num1: {{num1}}, num2: {{num2}}',
|
||||||
|
{ num1: 42, num2: 0 },
|
||||||
|
'num1: 42, num2: 0'
|
||||||
|
);
|
||||||
shouldCompileTo('num: {{.}}', 0, 'num: 0');
|
shouldCompileTo('num: {{.}}', 0, 'num: 0');
|
||||||
shouldCompileTo('num: {{num1/num2}}', { num1: { num2: 0 } }, 'num: 0');
|
shouldCompileTo('num: {{num1/num2}}', { num1: { num2: 0 } }, 'num: 0');
|
||||||
});
|
});
|
||||||
it('false', function() {
|
it('false', function() {
|
||||||
/* eslint-disable no-new-wrappers */
|
/* eslint-disable no-new-wrappers */
|
||||||
shouldCompileTo('val1: {{val1}}, val2: {{val2}}', {val1: false, val2: new Boolean(false)}, 'val1: false, val2: false');
|
shouldCompileTo(
|
||||||
|
'val1: {{val1}}, val2: {{val2}}',
|
||||||
|
{ val1: false, val2: new Boolean(false) },
|
||||||
|
'val1: false, val2: false'
|
||||||
|
);
|
||||||
shouldCompileTo('val: {{.}}', false, 'val: false');
|
shouldCompileTo('val: {{.}}', false, 'val: false');
|
||||||
shouldCompileTo('val: {{val1/val2}}', {val1: {val2: false}}, 'val: false');
|
shouldCompileTo(
|
||||||
|
'val: {{val1/val2}}',
|
||||||
|
{ val1: { val2: false } },
|
||||||
|
'val: false'
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileTo('val1: {{{val1}}}, val2: {{{val2}}}', {val1: false, val2: new Boolean(false)}, 'val1: false, val2: false');
|
shouldCompileTo(
|
||||||
shouldCompileTo('val: {{{val1/val2}}}', {val1: {val2: false}}, 'val: false');
|
'val1: {{{val1}}}, val2: {{{val2}}}',
|
||||||
|
{ val1: false, val2: new Boolean(false) },
|
||||||
|
'val1: false, val2: false'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'val: {{{val1/val2}}}',
|
||||||
|
{ val1: { val2: false } },
|
||||||
|
'val: false'
|
||||||
|
);
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle undefined and null', function() {
|
it('should handle undefined and null', function() {
|
||||||
shouldCompileTo('{{awesome undefined null}}',
|
shouldCompileTo(
|
||||||
|
'{{awesome undefined null}}',
|
||||||
{
|
{
|
||||||
awesome: function(_undefined, _null, options) {
|
awesome: function(_undefined, _null, options) {
|
||||||
return (_undefined === undefined) + ' ' + (_null === null) + ' ' + (typeof options);
|
return (
|
||||||
|
(_undefined === undefined) +
|
||||||
|
' ' +
|
||||||
|
(_null === null) +
|
||||||
|
' ' +
|
||||||
|
typeof options
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'true true object');
|
'true true object'
|
||||||
shouldCompileTo('{{undefined}}',
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{undefined}}',
|
||||||
{
|
{
|
||||||
'undefined': function() {
|
undefined: function() {
|
||||||
return 'undefined!';
|
return 'undefined!';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'undefined!');
|
'undefined!'
|
||||||
shouldCompileTo('{{null}}',
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{null}}',
|
||||||
{
|
{
|
||||||
'null': function() {
|
null: function() {
|
||||||
return 'null!';
|
return 'null!';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'null!');
|
'null!'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('newlines', function() {
|
it('newlines', function() {
|
||||||
@@ -101,118 +155,300 @@ describe('basic context', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('escaping text', function() {
|
it('escaping text', function() {
|
||||||
shouldCompileTo("Awesome's", {}, "Awesome's", "text is escaped so that it doesn't get caught on single quotes");
|
shouldCompileTo(
|
||||||
shouldCompileTo('Awesome\\', {}, 'Awesome\\', "text is escaped so that the closing quote can't be ignored");
|
"Awesome's",
|
||||||
shouldCompileTo('Awesome\\\\ foo', {}, 'Awesome\\\\ foo', "text is escaped so that it doesn't mess up backslashes");
|
{},
|
||||||
shouldCompileTo('Awesome {{foo}}', {foo: '\\'}, 'Awesome \\', "text is escaped so that it doesn't mess up backslashes");
|
"Awesome's",
|
||||||
shouldCompileTo(" ' ' ", {}, " ' ' ", 'double quotes never produce invalid javascript');
|
"text is escaped so that it doesn't get caught on single quotes"
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'Awesome\\',
|
||||||
|
{},
|
||||||
|
'Awesome\\',
|
||||||
|
"text is escaped so that the closing quote can't be ignored"
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'Awesome\\\\ foo',
|
||||||
|
{},
|
||||||
|
'Awesome\\\\ foo',
|
||||||
|
"text is escaped so that it doesn't mess up backslashes"
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'Awesome {{foo}}',
|
||||||
|
{ foo: '\\' },
|
||||||
|
'Awesome \\',
|
||||||
|
"text is escaped so that it doesn't mess up backslashes"
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
" ' ' ",
|
||||||
|
{},
|
||||||
|
" ' ' ",
|
||||||
|
'double quotes never produce invalid javascript'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('escaping expressions', function() {
|
it('escaping expressions', function() {
|
||||||
shouldCompileTo('{{{awesome}}}', {awesome: '&\'\\<>'}, '&\'\\<>',
|
shouldCompileTo(
|
||||||
"expressions with 3 handlebars aren't escaped");
|
'{{{awesome}}}',
|
||||||
|
{ awesome: "&'\\<>" },
|
||||||
|
"&'\\<>",
|
||||||
|
"expressions with 3 handlebars aren't escaped"
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileTo('{{&awesome}}', {awesome: '&\'\\<>'}, '&\'\\<>',
|
shouldCompileTo(
|
||||||
"expressions with {{& handlebars aren't escaped");
|
'{{&awesome}}',
|
||||||
|
{ awesome: "&'\\<>" },
|
||||||
|
"&'\\<>",
|
||||||
|
"expressions with {{& handlebars aren't escaped"
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileTo('{{awesome}}', {awesome: "&\"'`\\<>"}, '&"'`\\<>',
|
shouldCompileTo(
|
||||||
'by default expressions should be escaped');
|
'{{awesome}}',
|
||||||
|
{ awesome: '&"\'`\\<>' },
|
||||||
|
'&"'`\\<>',
|
||||||
|
'by default expressions should be escaped'
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileTo('{{awesome}}', {awesome: 'Escaped, <b> looks like: <b>'}, 'Escaped, <b> looks like: &lt;b&gt;',
|
shouldCompileTo(
|
||||||
'escaping should properly handle amperstands');
|
'{{awesome}}',
|
||||||
|
{ awesome: 'Escaped, <b> looks like: <b>' },
|
||||||
|
'Escaped, <b> looks like: &lt;b&gt;',
|
||||||
|
'escaping should properly handle amperstands'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("functions returning safestrings shouldn't be escaped", function() {
|
it("functions returning safestrings shouldn't be escaped", function() {
|
||||||
var hash = {awesome: function() { return new Handlebars.SafeString('&\'\\<>'); }};
|
var hash = {
|
||||||
shouldCompileTo('{{awesome}}', hash, '&\'\\<>',
|
awesome: function() {
|
||||||
"functions returning safestrings aren't escaped");
|
return new Handlebars.SafeString("&'\\<>");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{awesome}}',
|
||||||
|
hash,
|
||||||
|
"&'\\<>",
|
||||||
|
"functions returning safestrings aren't escaped"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('functions', function() {
|
it('functions', function() {
|
||||||
shouldCompileTo('{{awesome}}', {awesome: function() { return 'Awesome'; }}, 'Awesome',
|
shouldCompileTo(
|
||||||
'functions are called and render their output');
|
'{{awesome}}',
|
||||||
shouldCompileTo('{{awesome}}', {awesome: function() { return this.more; }, more: 'More awesome'}, 'More awesome',
|
{
|
||||||
'functions are bound to the context');
|
awesome: function() {
|
||||||
|
return 'Awesome';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Awesome',
|
||||||
|
'functions are called and render their output'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{awesome}}',
|
||||||
|
{
|
||||||
|
awesome: function() {
|
||||||
|
return this.more;
|
||||||
|
},
|
||||||
|
more: 'More awesome'
|
||||||
|
},
|
||||||
|
'More awesome',
|
||||||
|
'functions are bound to the context'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('functions with context argument', function() {
|
it('functions with context argument', function() {
|
||||||
shouldCompileTo('{{awesome frank}}',
|
shouldCompileTo(
|
||||||
{awesome: function(context) { return context; },
|
'{{awesome frank}}',
|
||||||
frank: 'Frank'},
|
{
|
||||||
'Frank', 'functions are called with context arguments');
|
awesome: function(context) {
|
||||||
|
return context;
|
||||||
|
},
|
||||||
|
frank: 'Frank'
|
||||||
|
},
|
||||||
|
'Frank',
|
||||||
|
'functions are called with context arguments'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('pathed functions with context argument', function() {
|
it('pathed functions with context argument', function() {
|
||||||
shouldCompileTo('{{bar.awesome frank}}',
|
shouldCompileTo(
|
||||||
{bar: {awesome: function(context) { return context; }},
|
'{{bar.awesome frank}}',
|
||||||
frank: 'Frank'},
|
{
|
||||||
'Frank', 'functions are called with context arguments');
|
bar: {
|
||||||
|
awesome: function(context) {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
frank: 'Frank'
|
||||||
|
},
|
||||||
|
'Frank',
|
||||||
|
'functions are called with context arguments'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('depthed functions with context argument', function() {
|
it('depthed functions with context argument', function() {
|
||||||
shouldCompileTo('{{#with frank}}{{../awesome .}}{{/with}}',
|
shouldCompileTo(
|
||||||
{awesome: function(context) { return context; },
|
'{{#with frank}}{{../awesome .}}{{/with}}',
|
||||||
frank: 'Frank'},
|
{
|
||||||
'Frank', 'functions are called with context arguments');
|
awesome: function(context) {
|
||||||
|
return context;
|
||||||
|
},
|
||||||
|
frank: 'Frank'
|
||||||
|
},
|
||||||
|
'Frank',
|
||||||
|
'functions are called with context arguments'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('block functions with context argument', function() {
|
it('block functions with context argument', function() {
|
||||||
shouldCompileTo('{{#awesome 1}}inner {{.}}{{/awesome}}',
|
shouldCompileTo(
|
||||||
{awesome: function(context, options) { return options.fn(context); }},
|
'{{#awesome 1}}inner {{.}}{{/awesome}}',
|
||||||
'inner 1', 'block functions are called with context and options');
|
{
|
||||||
|
awesome: function(context, options) {
|
||||||
|
return options.fn(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'inner 1',
|
||||||
|
'block functions are called with context and options'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('depthed block functions with context argument', function() {
|
it('depthed block functions with context argument', function() {
|
||||||
shouldCompileTo('{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}',
|
shouldCompileTo(
|
||||||
{value: true, awesome: function(context, options) { return options.fn(context); }},
|
'{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}',
|
||||||
'inner 1', 'block functions are called with context and options');
|
{
|
||||||
|
value: true,
|
||||||
|
awesome: function(context, options) {
|
||||||
|
return options.fn(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'inner 1',
|
||||||
|
'block functions are called with context and options'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('block functions without context argument', function() {
|
it('block functions without context argument', function() {
|
||||||
shouldCompileTo('{{#awesome}}inner{{/awesome}}',
|
shouldCompileTo(
|
||||||
{awesome: function(options) { return options.fn(this); }},
|
'{{#awesome}}inner{{/awesome}}',
|
||||||
'inner', 'block functions are called with options');
|
{
|
||||||
|
awesome: function(options) {
|
||||||
|
return options.fn(this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'inner',
|
||||||
|
'block functions are called with options'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('pathed block functions without context argument', function() {
|
it('pathed block functions without context argument', function() {
|
||||||
shouldCompileTo('{{#foo.awesome}}inner{{/foo.awesome}}',
|
shouldCompileTo(
|
||||||
{foo: {awesome: function() { return this; }}},
|
'{{#foo.awesome}}inner{{/foo.awesome}}',
|
||||||
'inner', 'block functions are called with options');
|
{
|
||||||
|
foo: {
|
||||||
|
awesome: function() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'inner',
|
||||||
|
'block functions are called with options'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('depthed block functions without context argument', function() {
|
it('depthed block functions without context argument', function() {
|
||||||
shouldCompileTo('{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}',
|
shouldCompileTo(
|
||||||
{value: true, awesome: function() { return this; }},
|
'{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}',
|
||||||
'inner', 'block functions are called with options');
|
{
|
||||||
|
value: true,
|
||||||
|
awesome: function() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'inner',
|
||||||
|
'block functions are called with options'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('paths with hyphens', function() {
|
it('paths with hyphens', function() {
|
||||||
shouldCompileTo('{{foo-bar}}', {'foo-bar': 'baz'}, 'baz', 'Paths can contain hyphens (-)');
|
shouldCompileTo(
|
||||||
shouldCompileTo('{{foo.foo-bar}}', {foo: {'foo-bar': 'baz'}}, 'baz', 'Paths can contain hyphens (-)');
|
'{{foo-bar}}',
|
||||||
shouldCompileTo('{{foo/foo-bar}}', {foo: {'foo-bar': 'baz'}}, 'baz', 'Paths can contain hyphens (-)');
|
{ 'foo-bar': 'baz' },
|
||||||
|
'baz',
|
||||||
|
'Paths can contain hyphens (-)'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{foo.foo-bar}}',
|
||||||
|
{ foo: { 'foo-bar': 'baz' } },
|
||||||
|
'baz',
|
||||||
|
'Paths can contain hyphens (-)'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{foo/foo-bar}}',
|
||||||
|
{ foo: { 'foo-bar': 'baz' } },
|
||||||
|
'baz',
|
||||||
|
'Paths can contain hyphens (-)'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('nested paths', function() {
|
it('nested paths', function() {
|
||||||
shouldCompileTo('Goodbye {{alan/expression}} world!', {alan: {expression: 'beautiful'}},
|
shouldCompileTo(
|
||||||
'Goodbye beautiful world!', 'Nested paths access nested objects');
|
'Goodbye {{alan/expression}} world!',
|
||||||
|
{ alan: { expression: 'beautiful' } },
|
||||||
|
'Goodbye beautiful world!',
|
||||||
|
'Nested paths access nested objects'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('nested paths with empty string value', function() {
|
it('nested paths with empty string value', function() {
|
||||||
shouldCompileTo('Goodbye {{alan/expression}} world!', {alan: {expression: ''}},
|
shouldCompileTo(
|
||||||
'Goodbye world!', 'Nested paths access nested objects with empty string');
|
'Goodbye {{alan/expression}} world!',
|
||||||
|
{ alan: { expression: '' } },
|
||||||
|
'Goodbye world!',
|
||||||
|
'Nested paths access nested objects with empty string'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('literal paths', function() {
|
it('literal paths', function() {
|
||||||
shouldCompileTo('Goodbye {{[@alan]/expression}} world!', {'@alan': {expression: 'beautiful'}},
|
shouldCompileTo(
|
||||||
'Goodbye beautiful world!', 'Literal paths can be used');
|
'Goodbye {{[@alan]/expression}} world!',
|
||||||
shouldCompileTo('Goodbye {{[foo bar]/expression}} world!', {'foo bar': {expression: 'beautiful'}},
|
{ '@alan': { expression: 'beautiful' } },
|
||||||
'Goodbye beautiful world!', 'Literal paths can be used');
|
'Goodbye beautiful world!',
|
||||||
|
'Literal paths can be used'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'Goodbye {{[foo bar]/expression}} world!',
|
||||||
|
{ 'foo bar': { expression: 'beautiful' } },
|
||||||
|
'Goodbye beautiful world!',
|
||||||
|
'Literal paths can be used'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('literal references', function() {
|
it('literal references', function() {
|
||||||
shouldCompileTo('Goodbye {{[foo bar]}} world!', {'foo bar': 'beautiful'}, 'Goodbye beautiful world!');
|
shouldCompileTo(
|
||||||
shouldCompileTo('Goodbye {{"foo bar"}} world!', {'foo bar': 'beautiful'}, 'Goodbye beautiful world!');
|
'Goodbye {{[foo bar]}} world!',
|
||||||
shouldCompileTo("Goodbye {{'foo bar'}} world!", {'foo bar': 'beautiful'}, 'Goodbye beautiful world!');
|
{ 'foo bar': 'beautiful' },
|
||||||
shouldCompileTo('Goodbye {{"foo[bar"}} world!', {'foo[bar': 'beautiful'}, 'Goodbye beautiful world!');
|
'Goodbye beautiful world!'
|
||||||
shouldCompileTo('Goodbye {{"foo\'bar"}} world!', {"foo'bar": 'beautiful'}, 'Goodbye beautiful world!');
|
);
|
||||||
shouldCompileTo("Goodbye {{'foo\"bar'}} world!", {'foo"bar': 'beautiful'}, 'Goodbye beautiful world!');
|
shouldCompileTo(
|
||||||
|
'Goodbye {{"foo bar"}} world!',
|
||||||
|
{ 'foo bar': 'beautiful' },
|
||||||
|
'Goodbye beautiful world!'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
"Goodbye {{'foo bar'}} world!",
|
||||||
|
{ 'foo bar': 'beautiful' },
|
||||||
|
'Goodbye beautiful world!'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'Goodbye {{"foo[bar"}} world!',
|
||||||
|
{ 'foo[bar': 'beautiful' },
|
||||||
|
'Goodbye beautiful world!'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'Goodbye {{"foo\'bar"}} world!',
|
||||||
|
{ "foo'bar": 'beautiful' },
|
||||||
|
'Goodbye beautiful world!'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
"Goodbye {{'foo\"bar'}} world!",
|
||||||
|
{ 'foo"bar': 'beautiful' },
|
||||||
|
'Goodbye beautiful world!'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("that current context path ({{.}}) doesn't hit helpers", function() {
|
it("that current context path ({{.}}) doesn't hit helpers", function() {
|
||||||
@@ -227,57 +463,105 @@ describe('basic context', function() {
|
|||||||
it('this keyword in paths', function() {
|
it('this keyword in paths', function() {
|
||||||
var string = '{{#goodbyes}}{{this}}{{/goodbyes}}';
|
var string = '{{#goodbyes}}{{this}}{{/goodbyes}}';
|
||||||
var hash = { goodbyes: ['goodbye', 'Goodbye', 'GOODBYE'] };
|
var hash = { goodbyes: ['goodbye', 'Goodbye', 'GOODBYE'] };
|
||||||
shouldCompileTo(string, hash, 'goodbyeGoodbyeGOODBYE',
|
shouldCompileTo(
|
||||||
'This keyword in paths evaluates to current context');
|
string,
|
||||||
|
hash,
|
||||||
|
'goodbyeGoodbyeGOODBYE',
|
||||||
|
'This keyword in paths evaluates to current context'
|
||||||
|
);
|
||||||
|
|
||||||
string = '{{#hellos}}{{this/text}}{{/hellos}}';
|
string = '{{#hellos}}{{this/text}}{{/hellos}}';
|
||||||
hash = {hellos: [{text: 'hello'}, {text: 'Hello'}, {text: 'HELLO'}]};
|
hash = {
|
||||||
shouldCompileTo(string, hash, 'helloHelloHELLO', 'This keyword evaluates in more complex paths');
|
hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }]
|
||||||
|
};
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
hash,
|
||||||
|
'helloHelloHELLO',
|
||||||
|
'This keyword evaluates in more complex paths'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('this keyword nested inside path', function() {
|
it('this keyword nested inside path', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
CompilerContext.compile('{{#hellos}}{{text/this/foo}}{{/hellos}}');
|
CompilerContext.compile('{{#hellos}}{{text/this/foo}}{{/hellos}}');
|
||||||
}, Error, 'Invalid path: text/this - 1:13');
|
},
|
||||||
|
Error,
|
||||||
|
'Invalid path: text/this - 1:13'
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileTo('{{[this]}}', {'this': 'bar'}, 'bar');
|
shouldCompileTo('{{[this]}}', { this: 'bar' }, 'bar');
|
||||||
shouldCompileTo('{{text/[this]}}', {text: {'this': 'bar'}}, 'bar');
|
shouldCompileTo('{{text/[this]}}', { text: { this: 'bar' } }, 'bar');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('this keyword in helpers', function() {
|
it('this keyword in helpers', function() {
|
||||||
var helpers = {foo: function(value) {
|
var helpers = {
|
||||||
|
foo: function(value) {
|
||||||
return 'bar ' + value;
|
return 'bar ' + value;
|
||||||
}};
|
}
|
||||||
|
};
|
||||||
var string = '{{#goodbyes}}{{foo this}}{{/goodbyes}}';
|
var string = '{{#goodbyes}}{{foo this}}{{/goodbyes}}';
|
||||||
var hash = { goodbyes: ['goodbye', 'Goodbye', 'GOODBYE'] };
|
var hash = { goodbyes: ['goodbye', 'Goodbye', 'GOODBYE'] };
|
||||||
shouldCompileTo(string, [hash, helpers], 'bar goodbyebar Goodbyebar GOODBYE',
|
shouldCompileTo(
|
||||||
'This keyword in paths evaluates to current context');
|
string,
|
||||||
|
[hash, helpers],
|
||||||
|
'bar goodbyebar Goodbyebar GOODBYE',
|
||||||
|
'This keyword in paths evaluates to current context'
|
||||||
|
);
|
||||||
|
|
||||||
string = '{{#hellos}}{{foo this/text}}{{/hellos}}';
|
string = '{{#hellos}}{{foo this/text}}{{/hellos}}';
|
||||||
hash = {hellos: [{text: 'hello'}, {text: 'Hello'}, {text: 'HELLO'}]};
|
hash = {
|
||||||
shouldCompileTo(string, [hash, helpers], 'bar hellobar Hellobar HELLO', 'This keyword evaluates in more complex paths');
|
hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }]
|
||||||
|
};
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
[hash, helpers],
|
||||||
|
'bar hellobar Hellobar HELLO',
|
||||||
|
'This keyword evaluates in more complex paths'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('this keyword nested inside helpers param', function() {
|
it('this keyword nested inside helpers param', function() {
|
||||||
var string = '{{#hellos}}{{foo text/this/foo}}{{/hellos}}';
|
var string = '{{#hellos}}{{foo text/this/foo}}{{/hellos}}';
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
CompilerContext.compile(string);
|
CompilerContext.compile(string);
|
||||||
}, Error, 'Invalid path: text/this - 1:17');
|
},
|
||||||
|
Error,
|
||||||
|
'Invalid path: text/this - 1:17'
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{foo [this]}}',
|
'{{foo [this]}}',
|
||||||
{foo: function(value) { return value; }, 'this': 'bar'},
|
{
|
||||||
'bar');
|
foo: function(value) {
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
this: 'bar'
|
||||||
|
},
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{foo text/[this]}}',
|
'{{foo text/[this]}}',
|
||||||
{foo: function(value) { return value; }, text: {'this': 'bar'}},
|
{
|
||||||
'bar');
|
foo: function(value) {
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
text: { this: 'bar' }
|
||||||
|
},
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('pass string literals', function() {
|
it('pass string literals', function() {
|
||||||
shouldCompileTo('{{"foo"}}', {}, '');
|
shouldCompileTo('{{"foo"}}', {}, '');
|
||||||
shouldCompileTo('{{"foo"}}', { foo: 'bar' }, 'bar');
|
shouldCompileTo('{{"foo"}}', { foo: 'bar' }, 'bar');
|
||||||
shouldCompileTo('{{#"foo"}}{{.}}{{/"foo"}}', { foo: ['bar', 'baz'] }, 'barbaz');
|
shouldCompileTo(
|
||||||
|
'{{#"foo"}}{{.}}{{/"foo"}}',
|
||||||
|
{ foo: ['bar', 'baz'] },
|
||||||
|
'barbaz'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('pass number literals', function() {
|
it('pass number literals', function() {
|
||||||
@@ -285,13 +569,21 @@ describe('basic context', function() {
|
|||||||
shouldCompileTo('{{12}}', { '12': 'bar' }, 'bar');
|
shouldCompileTo('{{12}}', { '12': 'bar' }, 'bar');
|
||||||
shouldCompileTo('{{12.34}}', {}, '');
|
shouldCompileTo('{{12.34}}', {}, '');
|
||||||
shouldCompileTo('{{12.34}}', { '12.34': 'bar' }, 'bar');
|
shouldCompileTo('{{12.34}}', { '12.34': 'bar' }, 'bar');
|
||||||
shouldCompileTo('{{12.34 1}}', { '12.34': function(arg) { return 'bar' + arg; } }, 'bar1');
|
shouldCompileTo(
|
||||||
|
'{{12.34 1}}',
|
||||||
|
{
|
||||||
|
'12.34': function(arg) {
|
||||||
|
return 'bar' + arg;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'bar1'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('pass boolean literals', function() {
|
it('pass boolean literals', function() {
|
||||||
shouldCompileTo('{{true}}', {}, '');
|
shouldCompileTo('{{true}}', {}, '');
|
||||||
shouldCompileTo('{{true}}', { '': 'foo' }, '');
|
shouldCompileTo('{{true}}', { '': 'foo' }, '');
|
||||||
shouldCompileTo('{{false}}', { 'false': 'foo' }, 'foo');
|
shouldCompileTo('{{false}}', { false: 'foo' }, 'foo');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle literals in subexpression', function() {
|
it('should handle literals in subexpression', function() {
|
||||||
@@ -300,6 +592,17 @@ describe('basic context', function() {
|
|||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
shouldCompileTo('{{foo (false)}}', [{ 'false': function() { return 'bar'; } }, helpers], 'bar');
|
shouldCompileTo(
|
||||||
|
'{{foo (false)}}',
|
||||||
|
[
|
||||||
|
{
|
||||||
|
false: function() {
|
||||||
|
return 'bar';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
helpers
|
||||||
|
],
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+237
-80
@@ -1,51 +1,99 @@
|
|||||||
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}}!';
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
var hash = {
|
||||||
shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!',
|
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }],
|
||||||
'Arrays iterate over the contents when not empty');
|
world: 'world'
|
||||||
|
};
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
hash,
|
||||||
|
'goodbye! Goodbye! GOODBYE! cruel world!',
|
||||||
|
'Arrays iterate over the contents when not empty'
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
|
shouldCompileTo(
|
||||||
'Arrays ignore the contents when empty');
|
string,
|
||||||
|
{ goodbyes: [], world: 'world' },
|
||||||
|
'cruel world!',
|
||||||
|
'Arrays ignore the contents when empty'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('array without data', function() {
|
it('array without data', function() {
|
||||||
var string = '{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}';
|
var string =
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
'{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}';
|
||||||
shouldCompileTo(string, [hash,,, false], 'goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE');
|
var hash = {
|
||||||
|
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }],
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
[hash, , , false],
|
||||||
|
'goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('array with @index', function() {
|
it('array with @index', function() {
|
||||||
var string = '{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
'{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }],
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
|
|
||||||
equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used');
|
equal(
|
||||||
|
result,
|
||||||
|
'0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!',
|
||||||
|
'The @index variable is used'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('empty block', function() {
|
it('empty block', function() {
|
||||||
var string = '{{#goodbyes}}{{/goodbyes}}cruel {{world}}!';
|
var string = '{{#goodbyes}}{{/goodbyes}}cruel {{world}}!';
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
var hash = {
|
||||||
shouldCompileTo(string, hash, 'cruel world!',
|
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }],
|
||||||
'Arrays iterate over the contents when not empty');
|
world: 'world'
|
||||||
|
};
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
hash,
|
||||||
|
'cruel world!',
|
||||||
|
'Arrays iterate over the contents when not empty'
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
|
shouldCompileTo(
|
||||||
'Arrays ignore the contents when empty');
|
string,
|
||||||
|
{ goodbyes: [], world: 'world' },
|
||||||
|
'cruel world!',
|
||||||
|
'Arrays ignore the contents when empty'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('block with complex lookup', function() {
|
it('block with complex lookup', function() {
|
||||||
var string = '{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}';
|
var string = '{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}';
|
||||||
var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]};
|
var hash = {
|
||||||
|
name: 'Alan',
|
||||||
|
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }]
|
||||||
|
};
|
||||||
|
|
||||||
shouldCompileTo(string, hash, 'goodbye cruel Alan! Goodbye cruel Alan! GOODBYE cruel Alan! ',
|
shouldCompileTo(
|
||||||
'Templates can access variables in contexts up the stack with relative path syntax');
|
string,
|
||||||
|
hash,
|
||||||
|
'goodbye cruel Alan! Goodbye cruel Alan! GOODBYE cruel Alan! ',
|
||||||
|
'Templates can access variables in contexts up the stack with relative path syntax'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('multiple blocks with complex lookup', function() {
|
it('multiple blocks with complex lookup', function() {
|
||||||
var string = '{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}';
|
var string = '{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}';
|
||||||
var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]};
|
var hash = {
|
||||||
|
name: 'Alan',
|
||||||
|
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }]
|
||||||
|
};
|
||||||
|
|
||||||
shouldCompileTo(string, hash, 'AlanAlanAlanAlanAlanAlan');
|
shouldCompileTo(string, hash, 'AlanAlanAlanAlanAlanAlan');
|
||||||
});
|
});
|
||||||
@@ -59,111 +107,201 @@ describe('blocks', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('block with deep nested complex lookup', function() {
|
it('block with deep nested complex lookup', function() {
|
||||||
var string = '{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}';
|
var string =
|
||||||
var hash = {omg: 'OMG!', outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }] };
|
'{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}';
|
||||||
|
var hash = {
|
||||||
|
omg: 'OMG!',
|
||||||
|
outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }]
|
||||||
|
};
|
||||||
|
|
||||||
shouldCompileTo(string, hash, 'Goodbye cruel sad OMG!');
|
shouldCompileTo(string, hash, 'Goodbye cruel sad OMG!');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('works with cached blocks', function() {
|
it('works with cached blocks', function() {
|
||||||
var template = CompilerContext.compile('{{#each person}}{{#with .}}{{first}} {{last}}{{/with}}{{/each}}', {data: false});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#each person}}{{#with .}}{{first}} {{last}}{{/with}}{{/each}}',
|
||||||
|
{ data: false }
|
||||||
|
);
|
||||||
|
|
||||||
var result = template({person: [{first: 'Alan', last: 'Johnson'}, {first: 'Alan', last: 'Johnson'}]});
|
var result = template({
|
||||||
|
person: [
|
||||||
|
{ first: 'Alan', last: 'Johnson' },
|
||||||
|
{ first: 'Alan', last: 'Johnson' }
|
||||||
|
]
|
||||||
|
});
|
||||||
equals(result, 'Alan JohnsonAlan Johnson');
|
equals(result, '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() {
|
||||||
var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
var string =
|
||||||
|
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
||||||
var hash = {};
|
var hash = {};
|
||||||
shouldCompileTo(string, hash, 'Right On!', "Inverted section rendered when value isn't set.");
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
hash,
|
||||||
|
'Right On!',
|
||||||
|
"Inverted section rendered when value isn't set."
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('inverted section with false value', function() {
|
it('inverted section with false value', function() {
|
||||||
var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
var string =
|
||||||
|
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
||||||
var hash = { goodbyes: false };
|
var hash = { goodbyes: false };
|
||||||
shouldCompileTo(string, hash, 'Right On!', 'Inverted section rendered when value is false.');
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
hash,
|
||||||
|
'Right On!',
|
||||||
|
'Inverted section rendered when value is false.'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('inverted section with empty set', function() {
|
it('inverted section with empty set', function() {
|
||||||
var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
var string =
|
||||||
|
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
||||||
var hash = { goodbyes: [] };
|
var hash = { goodbyes: [] };
|
||||||
shouldCompileTo(string, hash, 'Right On!', 'Inverted section rendered when value is empty set.');
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
hash,
|
||||||
|
'Right On!',
|
||||||
|
'Inverted section rendered when value is empty set.'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('block inverted sections', function() {
|
it('block inverted sections', function() {
|
||||||
shouldCompileTo('{{#people}}{{name}}{{^}}{{none}}{{/people}}', {none: 'No people'},
|
shouldCompileTo(
|
||||||
'No people');
|
'{{#people}}{{name}}{{^}}{{none}}{{/people}}',
|
||||||
|
{ none: 'No people' },
|
||||||
|
'No people'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('chained inverted sections', function() {
|
it('chained inverted sections', function() {
|
||||||
shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{/people}}', {none: 'No people'},
|
shouldCompileTo(
|
||||||
'No people');
|
'{{#people}}{{name}}{{else if none}}{{none}}{{/people}}',
|
||||||
shouldCompileTo('{{#people}}{{name}}{{else if nothere}}fail{{else unless nothere}}{{none}}{{/people}}', {none: 'No people'},
|
{ none: 'No people' },
|
||||||
'No people');
|
'No people'
|
||||||
shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{else}}fail{{/people}}', {none: 'No people'},
|
);
|
||||||
'No people');
|
shouldCompileTo(
|
||||||
|
'{{#people}}{{name}}{{else if nothere}}fail{{else unless nothere}}{{none}}{{/people}}',
|
||||||
|
{ none: 'No people' },
|
||||||
|
'No people'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{#people}}{{name}}{{else if none}}{{none}}{{else}}fail{{/people}}',
|
||||||
|
{ none: 'No people' },
|
||||||
|
'No people'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('chained inverted sections with mismatch', function() {
|
it('chained inverted sections with mismatch', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(function() {
|
||||||
shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{/if}}', {none: 'No people'},
|
shouldCompileTo(
|
||||||
'No people');
|
'{{#people}}{{name}}{{else if none}}{{none}}{{/if}}',
|
||||||
|
{ none: 'No people' },
|
||||||
|
'No people'
|
||||||
|
);
|
||||||
}, Error);
|
}, Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('block inverted sections with empty arrays', function() {
|
it('block inverted sections with empty arrays', function() {
|
||||||
shouldCompileTo('{{#people}}{{name}}{{^}}{{none}}{{/people}}', {none: 'No people', people: []},
|
shouldCompileTo(
|
||||||
'No people');
|
'{{#people}}{{name}}{{^}}{{none}}{{/people}}',
|
||||||
|
{ none: 'No people', people: [] },
|
||||||
|
'No people'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('standalone sections', function() {
|
describe('standalone sections', function() {
|
||||||
it('block standalone else sections', function() {
|
it('block standalone else sections', function() {
|
||||||
shouldCompileTo('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n', {none: 'No people'},
|
shouldCompileTo(
|
||||||
'No people\n');
|
'{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n',
|
||||||
shouldCompileTo('{{#none}}\n{{.}}\n{{^}}\n{{none}}\n{{/none}}\n', {none: 'No people'},
|
{ none: 'No people' },
|
||||||
'No people\n');
|
'No people\n'
|
||||||
shouldCompileTo('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n', {none: 'No people'},
|
);
|
||||||
'No people\n');
|
shouldCompileTo(
|
||||||
|
'{{#none}}\n{{.}}\n{{^}}\n{{none}}\n{{/none}}\n',
|
||||||
|
{ none: 'No people' },
|
||||||
|
'No people\n'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n',
|
||||||
|
{ none: 'No people' },
|
||||||
|
'No people\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('block standalone else sections can be disabled', function() {
|
it('block standalone else sections can be disabled', function() {
|
||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n',
|
'{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n',
|
||||||
[{ none: 'No people' }, {}, {}, { ignoreStandalone: true }],
|
[{ none: 'No people' }, {}, {}, { ignoreStandalone: true }],
|
||||||
'\nNo people\n\n');
|
'\nNo people\n\n'
|
||||||
|
);
|
||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{#none}}\n{{.}}\n{{^}}\nFail\n{{/none}}\n',
|
'{{#none}}\n{{.}}\n{{^}}\nFail\n{{/none}}\n',
|
||||||
[{ none: 'No people' }, {}, {}, { ignoreStandalone: true }],
|
[{ none: 'No people' }, {}, {}, { ignoreStandalone: true }],
|
||||||
'\nNo people\n\n');
|
'\nNo people\n\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('block standalone chained else sections', function() {
|
it('block standalone chained else sections', function() {
|
||||||
shouldCompileTo('{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{/people}}\n', {none: 'No people'},
|
shouldCompileTo(
|
||||||
'No people\n');
|
'{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{/people}}\n',
|
||||||
shouldCompileTo('{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{^}}\n{{/people}}\n', {none: 'No people'},
|
{ none: 'No people' },
|
||||||
'No people\n');
|
'No people\n'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{^}}\n{{/people}}\n',
|
||||||
|
{ none: 'No people' },
|
||||||
|
'No people\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should handle nesting', function() {
|
it('should handle nesting', function() {
|
||||||
shouldCompileTo('{{#data}}\n{{#if true}}\n{{.}}\n{{/if}}\n{{/data}}\nOK.', {data: [1, 3, 5]}, '1\n3\n5\nOK.');
|
shouldCompileTo(
|
||||||
|
'{{#data}}\n{{#if true}}\n{{.}}\n{{/if}}\n{{/data}}\nOK.',
|
||||||
|
{ data: [1, 3, 5] },
|
||||||
|
'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() {
|
||||||
var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}';
|
var string =
|
||||||
|
'{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}';
|
||||||
var hash = { omg: 'OMG!', outer: [{ inner: [{ text: 'goodbye' }] }] };
|
var hash = { omg: 'OMG!', outer: [{ inner: [{ text: 'goodbye' }] }] };
|
||||||
|
|
||||||
shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel OMG!');
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
[hash, undefined, undefined, true],
|
||||||
|
'Goodbye cruel OMG!'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('block with deep recursive pathed lookup', function() {
|
it('block with deep recursive pathed lookup', function() {
|
||||||
var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
|
var string =
|
||||||
var hash = {omg: {yes: 'OMG!'}, outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] };
|
'{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
|
||||||
|
var hash = {
|
||||||
|
omg: { yes: 'OMG!' },
|
||||||
|
outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }]
|
||||||
|
};
|
||||||
|
|
||||||
shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel OMG!');
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
[hash, undefined, undefined, true],
|
||||||
|
'Goodbye cruel OMG!'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('block with missed recursive lookup', function() {
|
it('block with missed recursive lookup', function() {
|
||||||
var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
|
var string =
|
||||||
var hash = {omg: {no: 'OMG!'}, outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] };
|
'{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
|
||||||
|
var hash = {
|
||||||
|
omg: { no: 'OMG!' },
|
||||||
|
outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }]
|
||||||
|
};
|
||||||
|
|
||||||
shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel ');
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
[hash, undefined, undefined, true],
|
||||||
|
'Goodbye cruel '
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -183,7 +321,8 @@ describe('blocks', function() {
|
|||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{#helper}}{{*decorator}}{{/helper}}',
|
'{{#helper}}{{*decorator}}{{/helper}}',
|
||||||
{ hash: {}, helpers: helpers, decorators: decorators },
|
{ hash: {}, helpers: helpers, decorators: decorators },
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should apply allow undefined return', function() {
|
it('should apply allow undefined return', function() {
|
||||||
var helpers = {
|
var helpers = {
|
||||||
@@ -199,7 +338,8 @@ describe('blocks', function() {
|
|||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{#helper}}{{*decorator}}suc{{/helper}}',
|
'{{#helper}}{{*decorator}}suc{{/helper}}',
|
||||||
{ hash: {}, helpers: helpers, decorators: decorators },
|
{ hash: {}, helpers: helpers, decorators: decorators },
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should apply block decorators', function() {
|
it('should apply block decorators', function() {
|
||||||
@@ -217,7 +357,8 @@ describe('blocks', function() {
|
|||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{#helper}}{{#*decorator}}success{{/decorator}}{{/helper}}',
|
'{{#helper}}{{#*decorator}}success{{/decorator}}{{/helper}}',
|
||||||
{ hash: {}, helpers: helpers, decorators: decorators },
|
{ hash: {}, helpers: helpers, decorators: decorators },
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should support nested decorators', function() {
|
it('should support nested decorators', function() {
|
||||||
var helpers = {
|
var helpers = {
|
||||||
@@ -237,7 +378,8 @@ describe('blocks', function() {
|
|||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{#helper}}{{#*decorator}}{{#*nested}}suc{{/nested}}cess{{/decorator}}{{/helper}}',
|
'{{#helper}}{{#*decorator}}{{#*nested}}suc{{/nested}}cess{{/decorator}}{{/helper}}',
|
||||||
{ hash: {}, helpers: helpers, decorators: decorators },
|
{ hash: {}, helpers: helpers, decorators: decorators },
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should apply multiple decorators', function() {
|
it('should apply multiple decorators', function() {
|
||||||
@@ -255,7 +397,8 @@ describe('blocks', function() {
|
|||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{#helper}}{{#*decorator}}suc{{/decorator}}{{#*decorator}}cess{{/decorator}}{{/helper}}',
|
'{{#helper}}{{#*decorator}}suc{{/decorator}}{{#*decorator}}cess{{/decorator}}{{/helper}}',
|
||||||
{ hash: {}, helpers: helpers, decorators: decorators },
|
{ hash: {}, helpers: helpers, decorators: decorators },
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should access parent variables', function() {
|
it('should access parent variables', function() {
|
||||||
@@ -272,8 +415,9 @@ describe('blocks', function() {
|
|||||||
};
|
};
|
||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{#helper}}{{*decorator foo}}{{/helper}}',
|
'{{#helper}}{{*decorator foo}}{{/helper}}',
|
||||||
{hash: {'foo': 'success'}, helpers: helpers, decorators: decorators},
|
{ hash: { foo: 'success' }, helpers: helpers, decorators: decorators },
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should work with root program', function() {
|
it('should work with root program', function() {
|
||||||
var run;
|
var run;
|
||||||
@@ -286,8 +430,9 @@ describe('blocks', function() {
|
|||||||
};
|
};
|
||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{*decorator "success"}}',
|
'{{*decorator "success"}}',
|
||||||
{hash: {'foo': 'success'}, decorators: decorators},
|
{ hash: { foo: 'success' }, decorators: decorators },
|
||||||
'');
|
''
|
||||||
|
);
|
||||||
equals(run, true);
|
equals(run, true);
|
||||||
});
|
});
|
||||||
it('should fail when accessing variables from root', function() {
|
it('should fail when accessing variables from root', function() {
|
||||||
@@ -301,8 +446,9 @@ describe('blocks', function() {
|
|||||||
};
|
};
|
||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{*decorator foo}}',
|
'{{*decorator foo}}',
|
||||||
{hash: {'foo': 'fail'}, decorators: decorators},
|
{ hash: { foo: 'fail' }, decorators: decorators },
|
||||||
'');
|
''
|
||||||
|
);
|
||||||
equals(run, true);
|
equals(run, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -335,12 +481,23 @@ 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(function() {
|
shouldThrow(
|
||||||
handlebarsEnv.registerDecorator({
|
function() {
|
||||||
world: function() { return 'world!'; },
|
handlebarsEnv.registerDecorator(
|
||||||
testHelper: function() { return 'found it!'; }
|
{
|
||||||
}, {});
|
world: function() {
|
||||||
}, Error, 'Arg not supported with multiple decorators');
|
return 'world!';
|
||||||
|
},
|
||||||
|
testHelper: function() {
|
||||||
|
return 'found it!';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Error,
|
||||||
|
'Arg not supported with multiple decorators'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+354
-91
@@ -2,62 +2,154 @@ 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}}!';
|
||||||
shouldCompileTo(string, {goodbye: true, world: 'world'}, 'GOODBYE cruel world!',
|
shouldCompileTo(
|
||||||
'if with boolean argument shows the contents when true');
|
string,
|
||||||
shouldCompileTo(string, {goodbye: 'dummy', world: 'world'}, 'GOODBYE cruel world!',
|
{ goodbye: true, world: 'world' },
|
||||||
'if with string argument shows the contents');
|
'GOODBYE cruel world!',
|
||||||
shouldCompileTo(string, {goodbye: false, world: 'world'}, 'cruel world!',
|
'if with boolean argument shows the contents when true'
|
||||||
'if with boolean argument does not show the contents when false');
|
);
|
||||||
shouldCompileTo(string, {world: 'world'}, 'cruel world!',
|
shouldCompileTo(
|
||||||
'if with undefined does not show the contents');
|
string,
|
||||||
shouldCompileTo(string, {goodbye: ['foo'], world: 'world'}, 'GOODBYE cruel world!',
|
{ goodbye: 'dummy', world: 'world' },
|
||||||
'if with non-empty array shows the contents');
|
'GOODBYE cruel world!',
|
||||||
shouldCompileTo(string, {goodbye: [], world: 'world'}, 'cruel world!',
|
'if with string argument shows the contents'
|
||||||
'if with empty array does not show the contents');
|
);
|
||||||
shouldCompileTo(string, {goodbye: 0, world: 'world'}, 'cruel world!',
|
shouldCompileTo(
|
||||||
'if with zero does not show the contents');
|
string,
|
||||||
shouldCompileTo('{{#if goodbye includeZero=true}}GOODBYE {{/if}}cruel {{world}}!',
|
{ goodbye: false, world: 'world' },
|
||||||
{goodbye: 0, world: 'world'}, 'GOODBYE cruel world!',
|
'cruel world!',
|
||||||
'if with zero does not show the contents');
|
'if with boolean argument does not show the contents when false'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ world: 'world' },
|
||||||
|
'cruel world!',
|
||||||
|
'if with undefined does not show the contents'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ goodbye: ['foo'], world: 'world' },
|
||||||
|
'GOODBYE cruel world!',
|
||||||
|
'if with non-empty array shows the contents'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ goodbye: [], world: 'world' },
|
||||||
|
'cruel world!',
|
||||||
|
'if with empty array does not show the contents'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ goodbye: 0, world: 'world' },
|
||||||
|
'cruel world!',
|
||||||
|
'if with zero does not show the contents'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{#if goodbye includeZero=true}}GOODBYE {{/if}}cruel {{world}}!',
|
||||||
|
{ goodbye: 0, world: 'world' },
|
||||||
|
'GOODBYE cruel world!',
|
||||||
|
'if with zero does not show the contents'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('if with function argument', function() {
|
it('if with function argument', function() {
|
||||||
var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!';
|
var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!';
|
||||||
shouldCompileTo(string, {goodbye: function() {return true; }, world: 'world'}, 'GOODBYE cruel world!',
|
shouldCompileTo(
|
||||||
'if with function shows the contents when function returns true');
|
string,
|
||||||
shouldCompileTo(string, {goodbye: function() {return this.world; }, world: 'world'}, 'GOODBYE cruel world!',
|
{
|
||||||
'if with function shows the contents when function returns string');
|
goodbye: function() {
|
||||||
shouldCompileTo(string, {goodbye: function() {return false; }, world: 'world'}, 'cruel world!',
|
return true;
|
||||||
'if with function does not show the contents when returns false');
|
},
|
||||||
shouldCompileTo(string, {goodbye: function() {return this.foo; }, world: 'world'}, 'cruel world!',
|
world: 'world'
|
||||||
'if with function does not show the contents when returns undefined');
|
},
|
||||||
|
'GOODBYE cruel world!',
|
||||||
|
'if with function shows the contents when function returns true'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
goodbye: function() {
|
||||||
|
return this.world;
|
||||||
|
},
|
||||||
|
world: 'world'
|
||||||
|
},
|
||||||
|
'GOODBYE cruel world!',
|
||||||
|
'if with function shows the contents when function returns string'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
goodbye: function() {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
world: 'world'
|
||||||
|
},
|
||||||
|
'cruel world!',
|
||||||
|
'if with function does not show the contents when returns false'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
goodbye: function() {
|
||||||
|
return this.foo;
|
||||||
|
},
|
||||||
|
world: 'world'
|
||||||
|
},
|
||||||
|
'cruel world!',
|
||||||
|
'if with function does not show the contents when returns undefined'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not change the depth list', function() {
|
it('should not change the depth list', function() {
|
||||||
var string = '{{#with foo}}{{#if goodbye}}GOODBYE cruel {{../world}}!{{/if}}{{/with}}';
|
var string =
|
||||||
shouldCompileTo(string, {foo: {goodbye: true}, world: 'world'}, 'GOODBYE cruel world!');
|
'{{#with foo}}{{#if goodbye}}GOODBYE cruel {{../world}}!{{/if}}{{/with}}';
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ foo: { goodbye: true }, world: 'world' },
|
||||||
|
'GOODBYE cruel world!'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#with', function() {
|
describe('#with', function() {
|
||||||
it('with', function() {
|
it('with', function() {
|
||||||
var string = '{{#with person}}{{first}} {{last}}{{/with}}';
|
var string = '{{#with person}}{{first}} {{last}}{{/with}}';
|
||||||
shouldCompileTo(string, {person: {first: 'Alan', last: 'Johnson'}}, 'Alan Johnson');
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ person: { first: 'Alan', last: 'Johnson' } },
|
||||||
|
'Alan Johnson'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('with with function argument', function() {
|
it('with with function argument', function() {
|
||||||
var string = '{{#with person}}{{first}} {{last}}{{/with}}';
|
var string = '{{#with person}}{{first}} {{last}}{{/with}}';
|
||||||
shouldCompileTo(string, {person: function() { return {first: 'Alan', last: 'Johnson'}; }}, 'Alan Johnson');
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
person: function() {
|
||||||
|
return { first: 'Alan', last: 'Johnson' };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Alan Johnson'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('with with else', function() {
|
it('with with else', function() {
|
||||||
var string = '{{#with person}}Person is present{{else}}Person is not present{{/with}}';
|
var string =
|
||||||
|
'{{#with person}}Person is present{{else}}Person is not present{{/with}}';
|
||||||
shouldCompileTo(string, {}, 'Person is not present');
|
shouldCompileTo(string, {}, 'Person is not present');
|
||||||
});
|
});
|
||||||
it('with provides block parameter', function() {
|
it('with provides block parameter', function() {
|
||||||
var string = '{{#with person as |foo|}}{{foo.first}} {{last}}{{/with}}';
|
var string = '{{#with person as |foo|}}{{foo.first}} {{last}}{{/with}}';
|
||||||
shouldCompileTo(string, {person: {first: 'Alan', last: 'Johnson'}}, 'Alan Johnson');
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ person: { first: 'Alan', last: 'Johnson' } },
|
||||||
|
'Alan Johnson'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('works when data is disabled', function() {
|
it('works when data is disabled', function() {
|
||||||
var template = CompilerContext.compile('{{#with person as |foo|}}{{foo.first}} {{last}}{{/with}}', {data: false});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#with person as |foo|}}{{foo.first}} {{last}}{{/with}}',
|
||||||
|
{ data: false }
|
||||||
|
);
|
||||||
|
|
||||||
var result = template({ person: { first: 'Alan', last: 'Johnson' } });
|
var result = template({ person: { first: 'Alan', last: 'Johnson' } });
|
||||||
equals(result, 'Alan Johnson');
|
equals(result, 'Alan Johnson');
|
||||||
@@ -73,20 +165,50 @@ describe('builtin helpers', function() {
|
|||||||
|
|
||||||
it('each', function() {
|
it('each', function() {
|
||||||
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
var hash = {
|
||||||
shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!',
|
goodbyes: [
|
||||||
'each with array argument iterates over the contents when not empty');
|
{ text: 'goodbye' },
|
||||||
shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
|
{ text: 'Goodbye' },
|
||||||
'each with array argument ignores the contents when empty');
|
{ text: 'GOODBYE' }
|
||||||
|
],
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
hash,
|
||||||
|
'goodbye! Goodbye! GOODBYE! cruel world!',
|
||||||
|
'each with array argument iterates over the contents when not empty'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ goodbyes: [], world: 'world' },
|
||||||
|
'cruel world!',
|
||||||
|
'each with array argument ignores the contents when empty'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('each without data', function() {
|
it('each without data', function() {
|
||||||
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
var hash = {
|
||||||
shouldCompileTo(string, [hash,,,, false], 'goodbye! Goodbye! GOODBYE! cruel world!');
|
goodbyes: [
|
||||||
|
{ text: 'goodbye' },
|
||||||
|
{ text: 'Goodbye' },
|
||||||
|
{ text: 'GOODBYE' }
|
||||||
|
],
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
[hash, , , , false],
|
||||||
|
'goodbye! Goodbye! GOODBYE! cruel world!'
|
||||||
|
);
|
||||||
|
|
||||||
hash = { goodbyes: 'cruel', world: 'world' };
|
hash = { goodbyes: 'cruel', world: 'world' };
|
||||||
shouldCompileTo('{{#each .}}{{.}}{{/each}}', [hash,,,, false], 'cruelworld');
|
shouldCompileTo(
|
||||||
|
'{{#each .}}{{.}}{{/each}}',
|
||||||
|
[hash, , , , false],
|
||||||
|
'cruelworld'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('each without context', function() {
|
it('each without context', function() {
|
||||||
@@ -95,7 +217,8 @@ describe('builtin helpers', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('each with an object and @key', function() {
|
it('each with an object and @key', function() {
|
||||||
var string = '{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!';
|
var string =
|
||||||
|
'{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!';
|
||||||
|
|
||||||
function Clazz() {
|
function Clazz() {
|
||||||
this['<b>#1</b>'] = { text: 'goodbye' };
|
this['<b>#1</b>'] = { text: 'goodbye' };
|
||||||
@@ -108,57 +231,113 @@ describe('builtin helpers', function() {
|
|||||||
// so we need to check both possible orders
|
// so we need to check both possible orders
|
||||||
// @see http://stackoverflow.com/questions/280713/elements-order-in-a-for-in-loop
|
// @see http://stackoverflow.com/questions/280713/elements-order-in-a-for-in-loop
|
||||||
var actual = compileWithPartials(string, hash);
|
var actual = compileWithPartials(string, hash);
|
||||||
var expected1 = '<b>#1</b>. goodbye! 2. GOODBYE! cruel world!';
|
var expected1 =
|
||||||
var expected2 = '2. GOODBYE! <b>#1</b>. goodbye! cruel world!';
|
'<b>#1</b>. goodbye! 2. GOODBYE! cruel world!';
|
||||||
|
var expected2 =
|
||||||
|
'2. GOODBYE! <b>#1</b>. goodbye! cruel world!';
|
||||||
|
|
||||||
equals(actual === expected1 || actual === expected2, true, 'each with object argument iterates over the contents when not empty');
|
equals(
|
||||||
|
actual === expected1 || actual === expected2,
|
||||||
|
true,
|
||||||
|
'each with object argument iterates over the contents when not empty'
|
||||||
|
);
|
||||||
shouldCompileTo(string, { goodbyes: {}, world: 'world' }, 'cruel world!');
|
shouldCompileTo(string, { goodbyes: {}, world: 'world' }, 'cruel world!');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('each with @index', function() {
|
it('each with @index', function() {
|
||||||
var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
'{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: [
|
||||||
|
{ text: 'goodbye' },
|
||||||
|
{ text: 'Goodbye' },
|
||||||
|
{ text: 'GOODBYE' }
|
||||||
|
],
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
|
|
||||||
equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used');
|
equal(
|
||||||
|
result,
|
||||||
|
'0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!',
|
||||||
|
'The @index variable is used'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('each with nested @index', function() {
|
it('each with nested @index', function() {
|
||||||
var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
'{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: [
|
||||||
|
{ text: 'goodbye' },
|
||||||
|
{ text: 'Goodbye' },
|
||||||
|
{ text: 'GOODBYE' }
|
||||||
|
],
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
|
|
||||||
equal(result, '0. goodbye! 0 1 2 After 0 1. Goodbye! 0 1 2 After 1 2. GOODBYE! 0 1 2 After 2 cruel world!', 'The @index variable is used');
|
equal(
|
||||||
|
result,
|
||||||
|
'0. goodbye! 0 1 2 After 0 1. Goodbye! 0 1 2 After 1 2. GOODBYE! 0 1 2 After 2 cruel world!',
|
||||||
|
'The @index variable is used'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('each with block params', function() {
|
it('each with block params', function() {
|
||||||
var string = '{{#each goodbyes as |value index|}}{{index}}. {{value.text}}! {{#each ../goodbyes as |childValue childIndex|}} {{index}} {{childIndex}}{{/each}} After {{index}} {{/each}}{{index}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}], world: 'world'};
|
'{{#each goodbyes as |value index|}}{{index}}. {{value.text}}! {{#each ../goodbyes as |childValue childIndex|}} {{index}} {{childIndex}}{{/each}} After {{index}} {{/each}}{{index}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }],
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
|
|
||||||
equal(result, '0. goodbye! 0 0 0 1 After 0 1. Goodbye! 1 0 1 1 After 1 cruel world!');
|
equal(
|
||||||
|
result,
|
||||||
|
'0. goodbye! 0 0 0 1 After 0 1. Goodbye! 1 0 1 1 After 1 cruel world!'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('each object with @index', function() {
|
it('each object with @index', function() {
|
||||||
var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: {'a': {text: 'goodbye'}, b: {text: 'Goodbye'}, c: {text: 'GOODBYE'}}, world: 'world'};
|
'{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: {
|
||||||
|
a: { text: 'goodbye' },
|
||||||
|
b: { text: 'Goodbye' },
|
||||||
|
c: { text: 'GOODBYE' }
|
||||||
|
},
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
|
|
||||||
equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used');
|
equal(
|
||||||
|
result,
|
||||||
|
'0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!',
|
||||||
|
'The @index variable is used'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('each with @first', function() {
|
it('each with @first', function() {
|
||||||
var string = '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
'{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: [
|
||||||
|
{ text: 'goodbye' },
|
||||||
|
{ text: 'Goodbye' },
|
||||||
|
{ text: 'GOODBYE' }
|
||||||
|
],
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
@@ -167,18 +346,34 @@ describe('builtin helpers', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('each with nested @first', function() {
|
it('each with nested @first', function() {
|
||||||
var string = '{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
'{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: [
|
||||||
|
{ text: 'goodbye' },
|
||||||
|
{ text: 'Goodbye' },
|
||||||
|
{ text: 'GOODBYE' }
|
||||||
|
],
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
|
|
||||||
equal(result, '(goodbye! goodbye! goodbye!) (goodbye!) (goodbye!) cruel world!', 'The @first variable is used');
|
equal(
|
||||||
|
result,
|
||||||
|
'(goodbye! goodbye! goodbye!) (goodbye!) (goodbye!) cruel world!',
|
||||||
|
'The @first variable is used'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('each object with @first', function() {
|
it('each object with @first', function() {
|
||||||
var string = '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: {'foo': {text: 'goodbye'}, bar: {text: 'Goodbye'}}, world: 'world'};
|
'{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: { foo: { text: 'goodbye' }, bar: { text: 'Goodbye' } },
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
@@ -187,8 +382,16 @@ describe('builtin helpers', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('each with @last', function() {
|
it('each with @last', function() {
|
||||||
var string = '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
'{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: [
|
||||||
|
{ text: 'goodbye' },
|
||||||
|
{ text: 'Goodbye' },
|
||||||
|
{ text: 'GOODBYE' }
|
||||||
|
],
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
@@ -197,8 +400,12 @@ describe('builtin helpers', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('each object with @last', function() {
|
it('each object with @last', function() {
|
||||||
var string = '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: {'foo': {text: 'goodbye'}, bar: {text: 'Goodbye'}}, world: 'world'};
|
'{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: { foo: { text: 'goodbye' }, bar: { text: 'Goodbye' } },
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
@@ -207,32 +414,73 @@ describe('builtin helpers', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('each with nested @last', function() {
|
it('each with nested @last', function() {
|
||||||
var string = '{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
|
'{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: [
|
||||||
|
{ text: 'goodbye' },
|
||||||
|
{ text: 'Goodbye' },
|
||||||
|
{ text: 'GOODBYE' }
|
||||||
|
],
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
|
|
||||||
equal(result, '(GOODBYE!) (GOODBYE!) (GOODBYE! GOODBYE! GOODBYE!) cruel world!', 'The @last variable is used');
|
equal(
|
||||||
|
result,
|
||||||
|
'(GOODBYE!) (GOODBYE!) (GOODBYE! GOODBYE! GOODBYE!) cruel world!',
|
||||||
|
'The @last variable is used'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('each with function argument', function() {
|
it('each with function argument', function() {
|
||||||
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
|
||||||
var hash = {goodbyes: function() { return [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]; }, world: 'world'};
|
var hash = {
|
||||||
shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!',
|
goodbyes: function() {
|
||||||
'each with array function argument iterates over the contents when not empty');
|
return [
|
||||||
shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
|
{ text: 'goodbye' },
|
||||||
'each with array function argument ignores the contents when empty');
|
{ text: 'Goodbye' },
|
||||||
|
{ text: 'GOODBYE' }
|
||||||
|
];
|
||||||
|
},
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
hash,
|
||||||
|
'goodbye! Goodbye! GOODBYE! cruel world!',
|
||||||
|
'each with array function argument iterates over the contents when not empty'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ goodbyes: [], world: 'world' },
|
||||||
|
'cruel world!',
|
||||||
|
'each with array function argument ignores the contents when empty'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('each object when last key is an empty string', function() {
|
it('each object when last key is an empty string', function() {
|
||||||
var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!';
|
var string =
|
||||||
var hash = {goodbyes: {'a': {text: 'goodbye'}, b: {text: 'Goodbye'}, '': {text: 'GOODBYE'}}, world: 'world'};
|
'{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!';
|
||||||
|
var hash = {
|
||||||
|
goodbyes: {
|
||||||
|
a: { text: 'goodbye' },
|
||||||
|
b: { text: 'Goodbye' },
|
||||||
|
'': { text: 'GOODBYE' }
|
||||||
|
},
|
||||||
|
world: 'world'
|
||||||
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile(string);
|
var template = CompilerContext.compile(string);
|
||||||
var result = template(hash);
|
var result = template(hash);
|
||||||
|
|
||||||
equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'Empty string key is not skipped');
|
equal(
|
||||||
|
result,
|
||||||
|
'0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!',
|
||||||
|
'Empty string key is not skipped'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('data passed to helpers', function() {
|
it('data passed to helpers', function() {
|
||||||
@@ -249,10 +497,16 @@ describe('builtin helpers', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('each on implicit context', function() {
|
it('each on implicit context', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
var template = CompilerContext.compile('{{#each}}{{text}}! {{/each}}cruel world!');
|
function() {
|
||||||
|
var template = CompilerContext.compile(
|
||||||
|
'{{#each}}{{text}}! {{/each}}cruel world!'
|
||||||
|
);
|
||||||
template({});
|
template({});
|
||||||
}, handlebarsEnv.Exception, 'Must pass iterator to #each');
|
},
|
||||||
|
handlebarsEnv.Exception,
|
||||||
|
'Must pass iterator to #each'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (global.Symbol && global.Symbol.iterator) {
|
if (global.Symbol && global.Symbol.iterator) {
|
||||||
@@ -276,13 +530,25 @@ describe('builtin helpers', 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}}!';
|
||||||
var goodbyes = new Iterable([{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]);
|
var goodbyes = new Iterable([
|
||||||
|
{ text: 'goodbye' },
|
||||||
|
{ text: 'Goodbye' },
|
||||||
|
{ text: 'GOODBYE' }
|
||||||
|
]);
|
||||||
var goodbyesEmpty = new Iterable([]);
|
var goodbyesEmpty = new Iterable([]);
|
||||||
var hash = { goodbyes: goodbyes, world: 'world' };
|
var hash = { goodbyes: goodbyes, world: 'world' };
|
||||||
shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!',
|
shouldCompileTo(
|
||||||
'each with array argument iterates over the contents when not empty');
|
string,
|
||||||
shouldCompileTo(string, {goodbyes: goodbyesEmpty, world: 'world'}, 'cruel world!',
|
hash,
|
||||||
'each with array argument ignores the contents when empty');
|
'goodbye! Goodbye! GOODBYE! cruel world!',
|
||||||
|
'each with array argument iterates over the contents when not empty'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ goodbyes: goodbyesEmpty, world: 'world' },
|
||||||
|
'cruel world!',
|
||||||
|
'each with array argument ignores the contents when empty'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -293,9 +559,7 @@ describe('builtin helpers', function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var $log,
|
var $log, $info, $error;
|
||||||
$info,
|
|
||||||
$error;
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
$log = console.log;
|
$log = console.log;
|
||||||
$info = console.info;
|
$info = console.info;
|
||||||
@@ -449,7 +713,6 @@ describe('builtin helpers', function() {
|
|||||||
/* 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() {
|
||||||
var string = '{{#each goodbyes}}{{lookup ../data .}}{{/each}}',
|
var string = '{{#each goodbyes}}{{lookup ../data .}}{{/each}}',
|
||||||
|
|||||||
+102
-25
@@ -13,37 +13,84 @@ describe('compiler', 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);
|
||||||
equal(compile('{{foo.bar baz "foo" true false bat=1}}').equals(compile('{{foo.bar baz "foo" true false bat=1}}')), true);
|
equal(
|
||||||
equal(compile('{{foo.bar (baz bat=1)}}').equals(compile('{{foo.bar (baz bat=1)}}')), true);
|
compile('{{foo.bar baz "foo" true false bat=1}}').equals(
|
||||||
equal(compile('{{#foo}} {{/foo}}').equals(compile('{{#foo}} {{/foo}}')), true);
|
compile('{{foo.bar baz "foo" true false bat=1}}')
|
||||||
|
),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
equal(
|
||||||
|
compile('{{foo.bar (baz bat=1)}}').equals(
|
||||||
|
compile('{{foo.bar (baz bat=1)}}')
|
||||||
|
),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
equal(
|
||||||
|
compile('{{#foo}} {{/foo}}').equals(compile('{{#foo}} {{/foo}}')),
|
||||||
|
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);
|
||||||
equal(compile('{{foo.bar baz bat=1}}').equals(compile('{{foo.bar bar bat=1}}')), false);
|
equal(
|
||||||
equal(compile('{{foo.bar (baz bat=1)}}').equals(compile('{{foo.bar (bar bat=1)}}')), false);
|
compile('{{foo.bar baz bat=1}}').equals(
|
||||||
equal(compile('{{#foo}} {{/foo}}').equals(compile('{{#bar}} {{/bar}}')), false);
|
compile('{{foo.bar bar bat=1}}')
|
||||||
equal(compile('{{#foo}} {{/foo}}').equals(compile('{{#foo}} {{foo}}{{/foo}}')), false);
|
),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
equal(
|
||||||
|
compile('{{foo.bar (baz bat=1)}}').equals(
|
||||||
|
compile('{{foo.bar (bar bat=1)}}')
|
||||||
|
),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
equal(
|
||||||
|
compile('{{#foo}} {{/foo}}').equals(compile('{{#bar}} {{/bar}}')),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
equal(
|
||||||
|
compile('{{#foo}} {{/foo}}').equals(
|
||||||
|
compile('{{#foo}} {{foo}}{{/foo}}')
|
||||||
|
),
|
||||||
|
false
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#compile', function() {
|
describe('#compile', function() {
|
||||||
it('should fail with invalid input', function() {
|
it('should fail with invalid input', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Handlebars.compile(null);
|
Handlebars.compile(null);
|
||||||
}, Error, 'You must pass a string or Handlebars AST to Handlebars.compile. You passed null');
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
'You must pass a string or Handlebars AST to Handlebars.compile. You passed null'
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Handlebars.compile({});
|
Handlebars.compile({});
|
||||||
}, Error, 'You must pass a string or Handlebars AST to Handlebars.compile. You passed [object Object]');
|
},
|
||||||
|
Error,
|
||||||
|
'You must pass a string or Handlebars AST to Handlebars.compile. You passed [object Object]'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
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(true, false, 'Statement must throw exception. This line should not be executed.');
|
equal(
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
'Statement must throw exception. This line should not be executed.'
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
equal(err.message, 'if doesn\'t match def - 2:5', 'Checking error message');
|
equal(
|
||||||
|
err.message,
|
||||||
|
"if doesn't match def - 2:5",
|
||||||
|
'Checking error message'
|
||||||
|
);
|
||||||
if (Object.getOwnPropertyDescriptor(err, 'column').writable) {
|
if (Object.getOwnPropertyDescriptor(err, 'column').writable) {
|
||||||
// In Safari 8, the column-property is read-only. This means that even if it is set with defineProperty,
|
// In Safari 8, the column-property is read-only. This means that even if it is set with defineProperty,
|
||||||
// its value won't change (https://github.com/jquery/esprima/issues/1290#issuecomment-132455482)
|
// its value won't change (https://github.com/jquery/esprima/issues/1290#issuecomment-132455482)
|
||||||
@@ -57,17 +104,28 @@ 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(true, false, 'Statement must throw exception. This line should not be executed.');
|
equal(
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
'Statement must throw exception. This line should not be executed.'
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
equal(Object.prototype.propertyIsEnumerable.call(err, 'column'), true, 'Checking error column');
|
equal(
|
||||||
|
Object.prototype.propertyIsEnumerable.call(err, 'column'),
|
||||||
|
true,
|
||||||
|
'Checking error column'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can utilize AST instance', function() {
|
it('can utilize AST instance', function() {
|
||||||
equal(Handlebars.compile({
|
equal(
|
||||||
|
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() {
|
||||||
@@ -77,31 +135,50 @@ 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(JSON.stringify(options, 0, 2), JSON.stringify({data: [{a: 'foo'}, {a: 'bar'}]}, 0, 2));
|
equal(
|
||||||
|
JSON.stringify(options, 0, 2),
|
||||||
|
JSON.stringify({ data: [{ a: 'foo' }, { a: 'bar' }] }, 0, 2)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
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(JSON.stringify(options, 0, 2), JSON.stringify({knownHelpers: {}}, 0, 2));
|
equal(
|
||||||
|
JSON.stringify(options, 0, 2),
|
||||||
|
JSON.stringify({ knownHelpers: {} }, 0, 2)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#precompile', function() {
|
describe('#precompile', function() {
|
||||||
it('should fail with invalid input', function() {
|
it('should fail with invalid input', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Handlebars.precompile(null);
|
Handlebars.precompile(null);
|
||||||
}, Error, 'You must pass a string or Handlebars AST to Handlebars.precompile. You passed null');
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
'You must pass a string or Handlebars AST to Handlebars.precompile. You passed null'
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Handlebars.precompile({});
|
Handlebars.precompile({});
|
||||||
}, Error, 'You must pass a string or Handlebars AST to Handlebars.precompile. You passed [object Object]');
|
},
|
||||||
|
Error,
|
||||||
|
'You must pass a string or Handlebars AST to Handlebars.precompile. You passed [object Object]'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can utilize AST instance', function() {
|
it('can utilize AST instance', function() {
|
||||||
equal(/return "Hello"/.test(Handlebars.precompile({
|
equal(
|
||||||
|
/return "Hello"/.test(
|
||||||
|
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() {
|
||||||
|
|||||||
+122
-29
@@ -8,7 +8,10 @@ describe('data', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({noun: 'cat'}, {helpers: helpers, data: {adjective: 'happy'}});
|
var result = template(
|
||||||
|
{ noun: 'cat' },
|
||||||
|
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||||
|
);
|
||||||
equals('happy cat', result, 'Data output by helper');
|
equals('happy cat', result, 'Data output by helper');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -19,7 +22,9 @@ describe('data', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('deep @foo triggers automatic top-level data', function() {
|
it('deep @foo triggers automatic top-level data', function() {
|
||||||
var template = CompilerContext.compile('{{#let world="world"}}{{#if foo}}{{#if foo}}Hello {{@world}}{{/if}}{{/if}}{{/let}}');
|
var template = CompilerContext.compile(
|
||||||
|
'{{#let world="world"}}{{#if foo}}{{#if foo}}Hello {{@world}}{{/if}}{{/if}}{{/let}}'
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = Handlebars.createFrame(handlebarsEnv.helpers);
|
var helpers = Handlebars.createFrame(handlebarsEnv.helpers);
|
||||||
|
|
||||||
@@ -47,7 +52,11 @@ describe('data', function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var result = template({}, { helpers: helpers, data: { world: 'world' } });
|
var result = template({}, { helpers: helpers, data: { world: 'world' } });
|
||||||
equals('Hello world', result, '@foo as a parameter retrieves template data');
|
equals(
|
||||||
|
'Hello world',
|
||||||
|
result,
|
||||||
|
'@foo as a parameter retrieves template data'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hash values can be looked up via @foo', function() {
|
it('hash values can be looked up via @foo', function() {
|
||||||
@@ -59,7 +68,11 @@ describe('data', function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var result = template({}, { helpers: helpers, data: { world: 'world' } });
|
var result = template({}, { helpers: helpers, data: { world: 'world' } });
|
||||||
equals('Hello world', result, '@foo as a parameter retrieves template data');
|
equals(
|
||||||
|
'Hello world',
|
||||||
|
result,
|
||||||
|
'@foo as a parameter retrieves template data'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('nested parameter data can be looked up via @foo.bar', function() {
|
it('nested parameter data can be looked up via @foo.bar', function() {
|
||||||
@@ -70,8 +83,15 @@ describe('data', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({}, { helpers: helpers, data: { world: {bar: 'world' } } });
|
var result = template(
|
||||||
equals('Hello world', result, '@foo as a parameter retrieves template data');
|
{},
|
||||||
|
{ helpers: helpers, data: { world: { bar: 'world' } } }
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
'Hello world',
|
||||||
|
result,
|
||||||
|
'@foo as a parameter retrieves template data'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('nested parameter data does not fail with @world.bar', function() {
|
it('nested parameter data does not fail with @world.bar', function() {
|
||||||
@@ -82,8 +102,15 @@ describe('data', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({}, { helpers: helpers, data: { foo: {bar: 'world' } } });
|
var result = template(
|
||||||
equals('Hello undefined', result, '@foo as a parameter retrieves template data');
|
{},
|
||||||
|
{ helpers: helpers, data: { foo: { bar: 'world' } } }
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
'Hello undefined',
|
||||||
|
result,
|
||||||
|
'@foo as a parameter retrieves template data'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parameter data throws when using complex scope references', function() {
|
it('parameter data throws when using complex scope references', function() {
|
||||||
@@ -96,17 +123,38 @@ describe('data', function() {
|
|||||||
|
|
||||||
it('data can be functions', function() {
|
it('data can be functions', function() {
|
||||||
var template = CompilerContext.compile('{{@hello}}');
|
var template = CompilerContext.compile('{{@hello}}');
|
||||||
var result = template({}, { data: { hello: function() { return 'hello'; } } });
|
var result = template(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
hello: function() {
|
||||||
|
return 'hello';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
equals('hello', result);
|
equals('hello', result);
|
||||||
});
|
});
|
||||||
it('data can be functions with params', function() {
|
it('data can be functions with params', function() {
|
||||||
var template = CompilerContext.compile('{{@hello "hello"}}');
|
var template = CompilerContext.compile('{{@hello "hello"}}');
|
||||||
var result = template({}, { data: { hello: function(arg) { return arg; } } });
|
var result = template(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
hello: function(arg) {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
equals('hello', result);
|
equals('hello', result);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('data is inherited downstream', function() {
|
it('data is inherited downstream', function() {
|
||||||
var template = CompilerContext.compile('{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}', { data: true });
|
var template = CompilerContext.compile(
|
||||||
|
'{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}',
|
||||||
|
{ data: true }
|
||||||
|
);
|
||||||
var helpers = {
|
var helpers = {
|
||||||
let: function(options) {
|
let: function(options) {
|
||||||
var frame = Handlebars.createFrame(options.data);
|
var frame = Handlebars.createFrame(options.data);
|
||||||
@@ -119,7 +167,10 @@ describe('data', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({ bar: { baz: 'hello world' } }, { helpers: helpers, data: {} });
|
var result = template(
|
||||||
|
{ bar: { baz: 'hello world' } },
|
||||||
|
{ helpers: helpers, data: {} }
|
||||||
|
);
|
||||||
equals('2hello world1', result, 'data variables are inherited downstream');
|
equals('2hello world1', result, 'data variables are inherited downstream');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -136,7 +187,10 @@ describe('data', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({noun: 'cat'}, {helpers: helpers, partials: partials, data: {adjective: 'happy'}});
|
var result = template(
|
||||||
|
{ noun: 'cat' },
|
||||||
|
{ helpers: helpers, partials: partials, data: { adjective: 'happy' } }
|
||||||
|
);
|
||||||
equals('happy cat', result, 'Data output by helper inside partial');
|
equals('happy cat', result, 'Data output by helper inside partial');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -149,12 +203,17 @@ describe('data', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({exclaim: true, world: 'world'}, {helpers: helpers, data: {adjective: 'happy'}});
|
var result = template(
|
||||||
|
{ exclaim: true, world: 'world' },
|
||||||
|
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||||
|
);
|
||||||
equals('happy world!', result, 'Data output by helper');
|
equals('happy world!', result, 'Data output by helper');
|
||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
||||||
var template = CompilerContext.compile('{{#hello}}{{world}}{{/hello}}', {data: true});
|
var template = CompilerContext.compile('{{#hello}}{{world}}{{/hello}}', {
|
||||||
|
data: true
|
||||||
|
});
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
hello: function(options) {
|
hello: function(options) {
|
||||||
@@ -165,12 +224,18 @@ describe('data', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({exclaim: true}, {helpers: helpers, data: {adjective: 'happy'}});
|
var result = template(
|
||||||
|
{ exclaim: true },
|
||||||
|
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||||
|
);
|
||||||
equals('happy world!', result, 'Data output by helper');
|
equals('happy world!', result, 'Data output by helper');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passing in data to a compiled function that expects data - works with block helpers that use ..', function() {
|
it('passing in data to a compiled function that expects data - works with block helpers that use ..', function() {
|
||||||
var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#hello}}{{world ../zomg}}{{/hello}}',
|
||||||
|
{ data: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
hello: function(options) {
|
hello: function(options) {
|
||||||
@@ -181,12 +246,18 @@ describe('data', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy'}});
|
var result = template(
|
||||||
|
{ exclaim: true, zomg: 'world' },
|
||||||
|
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||||
|
);
|
||||||
equals('happy world?', result, 'Data output by helper');
|
equals('happy world?', result, 'Data output by helper');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..', function() {
|
it('passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..', function() {
|
||||||
var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#hello}}{{world ../zomg}}{{/hello}}',
|
||||||
|
{ data: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
hello: function(options) {
|
hello: function(options) {
|
||||||
@@ -197,29 +268,43 @@ describe('data', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy', accessData: '#win'}});
|
var result = template(
|
||||||
|
{ exclaim: true, zomg: 'world' },
|
||||||
|
{ helpers: helpers, data: { adjective: 'happy', accessData: '#win' } }
|
||||||
|
);
|
||||||
equals('#win happy world?', result, 'Data output by helper');
|
equals('#win happy world?', result, 'Data output by helper');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('you can override inherited data when invoking a helper', function() {
|
it('you can override inherited data when invoking a helper', function() {
|
||||||
var template = CompilerContext.compile('{{#hello}}{{world zomg}}{{/hello}}', {data: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#hello}}{{world zomg}}{{/hello}}',
|
||||||
|
{ data: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
hello: function(options) {
|
hello: function(options) {
|
||||||
return options.fn({exclaim: '?', zomg: 'world'}, { data: {adjective: 'sad'} });
|
return options.fn(
|
||||||
|
{ exclaim: '?', zomg: 'world' },
|
||||||
|
{ data: { adjective: 'sad' } }
|
||||||
|
);
|
||||||
},
|
},
|
||||||
world: function(thing, options) {
|
world: function(thing, options) {
|
||||||
return options.data.adjective + ' ' + thing + (this.exclaim || '');
|
return options.data.adjective + ' ' + thing + (this.exclaim || '');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({exclaim: true, zomg: 'planet'}, {helpers: helpers, data: {adjective: 'happy'}});
|
var result = template(
|
||||||
|
{ exclaim: true, zomg: 'planet' },
|
||||||
|
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||||
|
);
|
||||||
equals('sad world?', result, 'Overriden data output by helper');
|
equals('sad world?', result, 'Overriden data output by helper');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
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() {
|
||||||
var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#hello}}{{world ../zomg}}{{/hello}}',
|
||||||
|
{ data: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
hello: function(options) {
|
hello: function(options) {
|
||||||
@@ -230,7 +315,10 @@ describe('data', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy'}});
|
var result = template(
|
||||||
|
{ exclaim: true, zomg: 'world' },
|
||||||
|
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||||
|
);
|
||||||
equals('sad world?', result, 'Overriden data output by helper');
|
equals('sad world?', result, 'Overriden data output by helper');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -252,8 +340,12 @@ 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() {
|
||||||
var template = CompilerContext.compile('{{#helper}}{{#helper}}{{@./depth}} {{@../depth}} {{@../../depth}}{{/helper}}{{/helper}}');
|
var template = CompilerContext.compile(
|
||||||
var result = template({foo: 'hello'}, {
|
'{{#helper}}{{#helper}}{{@./depth}} {{@../depth}} {{@../../depth}}{{/helper}}{{/helper}}'
|
||||||
|
);
|
||||||
|
var result = template(
|
||||||
|
{ foo: 'hello' },
|
||||||
|
{
|
||||||
helpers: {
|
helpers: {
|
||||||
helper: function(options) {
|
helper: function(options) {
|
||||||
var frame = Handlebars.createFrame(options.data);
|
var frame = Handlebars.createFrame(options.data);
|
||||||
@@ -264,7 +356,8 @@ describe('data', function() {
|
|||||||
data: {
|
data: {
|
||||||
depth: 0
|
depth: 0
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
equals('2 1 0', result);
|
equals('2 1 0', result);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Vendored
+4
-2
@@ -6,7 +6,6 @@ var fs = require('fs'),
|
|||||||
var chai = require('chai');
|
var chai = require('chai');
|
||||||
var dirtyChai = require('dirty-chai');
|
var dirtyChai = require('dirty-chai');
|
||||||
|
|
||||||
|
|
||||||
chai.use(dirtyChai);
|
chai.use(dirtyChai);
|
||||||
global.expect = chai.expect;
|
global.expect = chai.expect;
|
||||||
|
|
||||||
@@ -18,7 +17,10 @@ var filename = 'dist/handlebars.js';
|
|||||||
if (global.minimizedTest) {
|
if (global.minimizedTest) {
|
||||||
filename = 'dist/handlebars.min.js';
|
filename = 'dist/handlebars.min.js';
|
||||||
}
|
}
|
||||||
var distHandlebars = fs.readFileSync(require.resolve('../../' + filename), 'utf-8');
|
var distHandlebars = fs.readFileSync(
|
||||||
|
require.resolve('../../' + filename),
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
vm.runInThisContext(distHandlebars, filename);
|
vm.runInThisContext(distHandlebars, filename);
|
||||||
|
|
||||||
global.CompilerContext = {
|
global.CompilerContext = {
|
||||||
|
|||||||
Vendored
+47
-17
@@ -1,6 +1,6 @@
|
|||||||
var global = (function() {
|
var global = (function() {
|
||||||
return this;
|
return this;
|
||||||
}());
|
})();
|
||||||
|
|
||||||
var AssertError;
|
var AssertError;
|
||||||
if (Error.captureStackTrace) {
|
if (Error.captureStackTrace) {
|
||||||
@@ -28,10 +28,19 @@ global.shouldCompileTo = function(string, hashOrArray, expected, message) {
|
|||||||
/**
|
/**
|
||||||
* @deprecated Use "expectTemplate(template)...toCompileTo(output)" instead
|
* @deprecated Use "expectTemplate(template)...toCompileTo(output)" instead
|
||||||
*/
|
*/
|
||||||
global.shouldCompileToWithPartials = function shouldCompileToWithPartials(string, hashOrArray, partials, expected, message) {
|
global.shouldCompileToWithPartials = function shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
hashOrArray,
|
||||||
|
partials,
|
||||||
|
expected,
|
||||||
|
message
|
||||||
|
) {
|
||||||
var result = compileWithPartials(string, hashOrArray, partials);
|
var result = compileWithPartials(string, hashOrArray, partials);
|
||||||
if (result !== expected) {
|
if (result !== expected) {
|
||||||
throw new AssertError("'" + result + "' should === '" + expected + "': " + message, shouldCompileToWithPartials);
|
throw new AssertError(
|
||||||
|
"'" + result + "' should === '" + expected + "': " + message,
|
||||||
|
shouldCompileToWithPartials
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,9 +48,7 @@ global.shouldCompileToWithPartials = function shouldCompileToWithPartials(string
|
|||||||
* @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,
|
var template, ary, options;
|
||||||
ary,
|
|
||||||
options;
|
|
||||||
if (hashOrArray && hashOrArray.hash) {
|
if (hashOrArray && hashOrArray.hash) {
|
||||||
ary = [hashOrArray.hash, hashOrArray];
|
ary = [hashOrArray.hash, hashOrArray];
|
||||||
delete hashOrArray.hash;
|
delete hashOrArray.hash;
|
||||||
@@ -49,7 +56,10 @@ global.compileWithPartials = function(string, hashOrArray, partials) {
|
|||||||
ary = [];
|
ary = [];
|
||||||
ary.push(hashOrArray[0]); // input
|
ary.push(hashOrArray[0]); // input
|
||||||
ary.push({ helpers: hashOrArray[1], partials: hashOrArray[2] });
|
ary.push({ helpers: hashOrArray[1], partials: hashOrArray[2] });
|
||||||
options = typeof hashOrArray[3] === 'object' ? hashOrArray[3] : {compat: hashOrArray[3]};
|
options =
|
||||||
|
typeof hashOrArray[3] === 'object'
|
||||||
|
? hashOrArray[3]
|
||||||
|
: { compat: hashOrArray[3] };
|
||||||
if (hashOrArray[4] != null) {
|
if (hashOrArray[4] != null) {
|
||||||
options.data = !!hashOrArray[4];
|
options.data = !!hashOrArray[4];
|
||||||
ary[1].data = hashOrArray[4];
|
ary[1].data = hashOrArray[4];
|
||||||
@@ -58,18 +68,23 @@ global.compileWithPartials = function(string, hashOrArray, partials) {
|
|||||||
ary = [hashOrArray];
|
ary = [hashOrArray];
|
||||||
}
|
}
|
||||||
|
|
||||||
template = CompilerContext[partials ? 'compileWithPartial' : 'compile'](string, options);
|
template = CompilerContext[partials ? 'compileWithPartial' : 'compile'](
|
||||||
|
string,
|
||||||
|
options
|
||||||
|
);
|
||||||
return template.apply(this, ary);
|
return template.apply(this, ary);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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/
|
* @see https://www.chaijs.com/api/bdd/
|
||||||
*/
|
*/
|
||||||
global.equals = global.equal = function equals(a, b, msg) {
|
global.equals = global.equal = function equals(a, b, msg) {
|
||||||
if (a !== b) {
|
if (a !== b) {
|
||||||
throw new AssertError("'" + a + "' should === '" + b + "'" + (msg ? ': ' + msg : ''), equals);
|
throw new AssertError(
|
||||||
|
"'" + a + "' should === '" + b + "'" + (msg ? ': ' + msg : ''),
|
||||||
|
equals
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,8 +101,19 @@ global.shouldThrow = function(callback, type, msg) {
|
|||||||
if (type && !(caught instanceof type)) {
|
if (type && !(caught instanceof type)) {
|
||||||
throw new AssertError('Type failure: ' + caught);
|
throw new AssertError('Type failure: ' + caught);
|
||||||
}
|
}
|
||||||
if (msg && !(msg.test ? msg.test(caught.message) : msg === caught.message)) {
|
if (
|
||||||
throw new AssertError('Throw mismatch: Expected ' + caught.message + ' to match ' + msg + '\n\n' + caught.stack, shouldThrow);
|
msg &&
|
||||||
|
!(msg.test ? msg.test(caught.message) : msg === caught.message)
|
||||||
|
) {
|
||||||
|
throw new AssertError(
|
||||||
|
'Throw mismatch: Expected ' +
|
||||||
|
caught.message +
|
||||||
|
' to match ' +
|
||||||
|
msg +
|
||||||
|
'\n\n' +
|
||||||
|
caught.stack,
|
||||||
|
shouldThrow
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (failed) {
|
if (failed) {
|
||||||
@@ -95,18 +121,17 @@ global.shouldThrow = function(callback, type, msg) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
global.expectTemplate = function(templateAsString) {
|
global.expectTemplate = function(templateAsString) {
|
||||||
return new HandlebarsTestBench(templateAsString);
|
return new HandlebarsTestBench(templateAsString);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function HandlebarsTestBench(templateAsString) {
|
function HandlebarsTestBench(templateAsString) {
|
||||||
this.templateAsString = templateAsString;
|
this.templateAsString = templateAsString;
|
||||||
this.helpers = {};
|
this.helpers = {};
|
||||||
this.partials = {};
|
this.partials = {};
|
||||||
this.input = {};
|
this.input = {};
|
||||||
this.message = 'Template' + templateAsString + ' does not evaluate to expected output';
|
this.message =
|
||||||
|
'Template' + templateAsString + ' does not evaluate to expected output';
|
||||||
this.compileOptions = {};
|
this.compileOptions = {};
|
||||||
this.runtimeOptions = {};
|
this.runtimeOptions = {};
|
||||||
}
|
}
|
||||||
@@ -146,7 +171,11 @@ 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, msg) {
|
HandlebarsTestBench.prototype.toThrow = function(
|
||||||
|
errorLike,
|
||||||
|
errMsgMatcher,
|
||||||
|
msg
|
||||||
|
) {
|
||||||
var self = this;
|
var self = this;
|
||||||
expect(function() {
|
expect(function() {
|
||||||
self._compileAndExeute();
|
self._compileAndExeute();
|
||||||
@@ -154,7 +183,8 @@ HandlebarsTestBench.prototype.toThrow = function(errorLike, errMsgMatcher, msg)
|
|||||||
};
|
};
|
||||||
|
|
||||||
HandlebarsTestBench.prototype._compileAndExeute = function() {
|
HandlebarsTestBench.prototype._compileAndExeute = function() {
|
||||||
var compile = Object.keys(this.partials).length > 0
|
var compile =
|
||||||
|
Object.keys(this.partials).length > 0
|
||||||
? CompilerContext.compileWithPartial
|
? CompilerContext.compileWithPartial
|
||||||
: CompilerContext.compile;
|
: CompilerContext.compile;
|
||||||
|
|
||||||
|
|||||||
Vendored
-1
@@ -3,7 +3,6 @@ require('./common');
|
|||||||
var chai = require('chai');
|
var chai = require('chai');
|
||||||
var dirtyChai = require('dirty-chai');
|
var dirtyChai = require('dirty-chai');
|
||||||
|
|
||||||
|
|
||||||
chai.use(dirtyChai);
|
chai.use(dirtyChai);
|
||||||
global.expect = chai.expect;
|
global.expect = chai.expect;
|
||||||
|
|
||||||
|
|||||||
Vendored
+8
-4
@@ -13,9 +13,14 @@ if (grep === '--min') {
|
|||||||
grep = undefined;
|
grep = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
var files = fs.readdirSync(testDir)
|
var files = fs
|
||||||
.filter(function(name) { return (/.*\.js$/).test(name); })
|
.readdirSync(testDir)
|
||||||
.map(function(name) { return testDir + path.sep + name; });
|
.filter(function(name) {
|
||||||
|
return /.*\.js$/.test(name);
|
||||||
|
})
|
||||||
|
.map(function(name) {
|
||||||
|
return testDir + path.sep + name;
|
||||||
|
});
|
||||||
|
|
||||||
if (global.minimizedTest) {
|
if (global.minimizedTest) {
|
||||||
run('./runtime', function() {
|
run('./runtime', function() {
|
||||||
@@ -37,7 +42,6 @@ if (global.minimizedTest) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function run(env, callback) {
|
function run(env, callback) {
|
||||||
var mocha = new Mocha();
|
var mocha = new Mocha();
|
||||||
mocha.ui('bdd');
|
mocha.ui('bdd');
|
||||||
|
|||||||
Vendored
+9
-3
@@ -6,7 +6,6 @@ var fs = require('fs'),
|
|||||||
var chai = require('chai');
|
var chai = require('chai');
|
||||||
var dirtyChai = require('dirty-chai');
|
var dirtyChai = require('dirty-chai');
|
||||||
|
|
||||||
|
|
||||||
chai.use(dirtyChai);
|
chai.use(dirtyChai);
|
||||||
global.expect = chai.expect;
|
global.expect = chai.expect;
|
||||||
|
|
||||||
@@ -18,7 +17,10 @@ var filename = 'dist/handlebars.runtime.js';
|
|||||||
if (global.minimizedTest) {
|
if (global.minimizedTest) {
|
||||||
filename = 'dist/handlebars.runtime.min.js';
|
filename = 'dist/handlebars.runtime.min.js';
|
||||||
}
|
}
|
||||||
vm.runInThisContext(fs.readFileSync(__dirname + '/../../' + filename), filename);
|
vm.runInThisContext(
|
||||||
|
fs.readFileSync(__dirname + '/../../' + filename),
|
||||||
|
filename
|
||||||
|
);
|
||||||
|
|
||||||
var parse = require('../../dist/cjs/handlebars/compiler/base').parse;
|
var parse = require('../../dist/cjs/handlebars/compiler/base').parse;
|
||||||
var compiler = require('../../dist/cjs/handlebars/compiler/compiler');
|
var compiler = require('../../dist/cjs/handlebars/compiler/compiler');
|
||||||
@@ -30,7 +32,11 @@ global.CompilerContext = {
|
|||||||
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(precompileTemplate, precompileOptions, handlebarsEnv);
|
return compiler.precompile(
|
||||||
|
precompileTemplate,
|
||||||
|
precompileOptions,
|
||||||
|
handlebarsEnv
|
||||||
|
);
|
||||||
};
|
};
|
||||||
handlebarsEnv.parse = parse;
|
handlebarsEnv.parse = parse;
|
||||||
handlebarsEnv.Compiler = compiler.Compiler;
|
handlebarsEnv.Compiler = compiler.Compiler;
|
||||||
|
|||||||
+677
-181
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,10 @@ describe('javascript-compiler api', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should allow override', function() {
|
it('should allow override', function() {
|
||||||
handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = function(parent, name) {
|
handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = function(
|
||||||
|
parent,
|
||||||
|
name
|
||||||
|
) {
|
||||||
return parent + '.bar_' + name;
|
return parent + '.bar_' + name;
|
||||||
};
|
};
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
@@ -43,7 +46,7 @@ describe('javascript-compiler api', function() {
|
|||||||
};
|
};
|
||||||
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");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
shouldCompileTo('{{foo}} ', { foo: 'food' }, 'food ');
|
shouldCompileTo('{{foo}} ', { foo: 'food' }, 'food ');
|
||||||
@@ -54,7 +57,8 @@ describe('javascript-compiler api', function() {
|
|||||||
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 = handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer;
|
$superCreate =
|
||||||
|
handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer;
|
||||||
});
|
});
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
handlebarsEnv.JavaScriptCompiler.prototype.forceBuffer = false;
|
handlebarsEnv.JavaScriptCompiler.prototype.forceBuffer = false;
|
||||||
@@ -69,7 +73,9 @@ describe('javascript-compiler api', function() {
|
|||||||
shouldCompileTo('{{foo}} ', { foo: 'food' }, 'foo_food ');
|
shouldCompileTo('{{foo}} ', { foo: 'food' }, 'foo_food ');
|
||||||
});
|
});
|
||||||
it('should allow append buffer override', function() {
|
it('should allow append buffer override', function() {
|
||||||
handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = function(string) {
|
handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = function(
|
||||||
|
string
|
||||||
|
) {
|
||||||
return $superAppend.call(this, [string, ' + "_foo"']);
|
return $superAppend.call(this, [string, ' + "_foo"']);
|
||||||
};
|
};
|
||||||
shouldCompileTo('{{foo}}', { foo: 'food' }, 'food_foo');
|
shouldCompileTo('{{foo}}', { foo: 'food' }, 'food_foo');
|
||||||
|
|||||||
+236
-74
@@ -68,7 +68,10 @@ describe('parser', function() {
|
|||||||
equals(astFor('{{null}}'), '{{ NULL [] }}\n');
|
equals(astFor('{{null}}'), '{{ NULL [] }}\n');
|
||||||
});
|
});
|
||||||
it('parses mustaches with undefined and null parameters', function() {
|
it('parses mustaches with undefined and null parameters', function() {
|
||||||
equals(astFor('{{foo undefined null}}'), '{{ PATH:foo [UNDEFINED, NULL] }}\n');
|
equals(
|
||||||
|
astFor('{{foo undefined null}}'),
|
||||||
|
'{{ PATH:foo [UNDEFINED, NULL] }}\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses mustaches with DATA parameters', function() {
|
it('parses mustaches with DATA parameters', function() {
|
||||||
@@ -78,23 +81,53 @@ describe('parser', function() {
|
|||||||
it('parses mustaches with hash arguments', function() {
|
it('parses mustaches with hash arguments', function() {
|
||||||
equals(astFor('{{foo bar=baz}}'), '{{ PATH:foo [] HASH{bar=PATH:baz} }}\n');
|
equals(astFor('{{foo bar=baz}}'), '{{ PATH:foo [] HASH{bar=PATH:baz} }}\n');
|
||||||
equals(astFor('{{foo bar=1}}'), '{{ PATH:foo [] HASH{bar=NUMBER{1}} }}\n');
|
equals(astFor('{{foo bar=1}}'), '{{ PATH:foo [] HASH{bar=NUMBER{1}} }}\n');
|
||||||
equals(astFor('{{foo bar=true}}'), '{{ PATH:foo [] HASH{bar=BOOLEAN{true}} }}\n');
|
equals(
|
||||||
equals(astFor('{{foo bar=false}}'), '{{ PATH:foo [] HASH{bar=BOOLEAN{false}} }}\n');
|
astFor('{{foo bar=true}}'),
|
||||||
equals(astFor('{{foo bar=@baz}}'), '{{ PATH:foo [] HASH{bar=@PATH:baz} }}\n');
|
'{{ PATH:foo [] HASH{bar=BOOLEAN{true}} }}\n'
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
astFor('{{foo bar=false}}'),
|
||||||
|
'{{ PATH:foo [] HASH{bar=BOOLEAN{false}} }}\n'
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
astFor('{{foo bar=@baz}}'),
|
||||||
|
'{{ PATH:foo [] HASH{bar=@PATH:baz} }}\n'
|
||||||
|
);
|
||||||
|
|
||||||
equals(astFor('{{foo bar=baz bat=bam}}'), '{{ PATH:foo [] HASH{bar=PATH:baz, bat=PATH:bam} }}\n');
|
equals(
|
||||||
equals(astFor('{{foo bar=baz bat="bam"}}'), '{{ PATH:foo [] HASH{bar=PATH:baz, bat="bam"} }}\n');
|
astFor('{{foo bar=baz bat=bam}}'),
|
||||||
|
'{{ PATH:foo [] HASH{bar=PATH:baz, bat=PATH:bam} }}\n'
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
astFor('{{foo bar=baz bat="bam"}}'),
|
||||||
|
'{{ PATH:foo [] HASH{bar=PATH:baz, bat="bam"} }}\n'
|
||||||
|
);
|
||||||
|
|
||||||
equals(astFor("{{foo bat='bam'}}"), '{{ PATH:foo [] HASH{bat="bam"} }}\n');
|
equals(astFor("{{foo bat='bam'}}"), '{{ PATH:foo [] HASH{bat="bam"} }}\n');
|
||||||
|
|
||||||
equals(astFor('{{foo omg bar=baz bat="bam"}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n');
|
equals(
|
||||||
equals(astFor('{{foo omg bar=baz bat="bam" baz=1}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n');
|
astFor('{{foo omg bar=baz bat="bam"}}'),
|
||||||
equals(astFor('{{foo omg bar=baz bat="bam" baz=true}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n');
|
'{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n'
|
||||||
equals(astFor('{{foo omg bar=baz bat="bam" baz=false}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n');
|
);
|
||||||
|
equals(
|
||||||
|
astFor('{{foo omg bar=baz bat="bam" baz=1}}'),
|
||||||
|
'{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n'
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
astFor('{{foo omg bar=baz bat="bam" baz=true}}'),
|
||||||
|
'{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n'
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
astFor('{{foo omg bar=baz bat="bam" baz=false}}'),
|
||||||
|
'{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses contents followed by a mustache', function() {
|
it('parses contents followed by a mustache', function() {
|
||||||
equals(astFor('foo bar {{baz}}'), 'CONTENT[ \'foo bar \' ]\n{{ PATH:baz [] }}\n');
|
equals(
|
||||||
|
astFor('foo bar {{baz}}'),
|
||||||
|
"CONTENT[ 'foo bar ' ]\n{{ PATH:baz [] }}\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses a partial', function() {
|
it('parses a partial', function() {
|
||||||
@@ -108,47 +141,81 @@ describe('parser', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('parses a partial with hash', function() {
|
it('parses a partial with hash', function() {
|
||||||
equals(astFor('{{> foo bar=bat}}'), '{{> PARTIAL:foo HASH{bar=PATH:bat} }}\n');
|
equals(
|
||||||
|
astFor('{{> foo bar=bat}}'),
|
||||||
|
'{{> PARTIAL:foo HASH{bar=PATH:bat} }}\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses a partial with context and hash', function() {
|
it('parses a partial with context and hash', function() {
|
||||||
equals(astFor('{{> foo bar bat=baz}}'), '{{> PARTIAL:foo PATH:bar HASH{bat=PATH:baz} }}\n');
|
equals(
|
||||||
|
astFor('{{> foo bar bat=baz}}'),
|
||||||
|
'{{> PARTIAL:foo PATH:bar HASH{bat=PATH:baz} }}\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses a partial with a complex name', function() {
|
it('parses a partial with a complex name', function() {
|
||||||
equals(astFor('{{> shared/partial?.bar}}'), '{{> PARTIAL:shared/partial?.bar }}\n');
|
equals(
|
||||||
|
astFor('{{> shared/partial?.bar}}'),
|
||||||
|
'{{> PARTIAL:shared/partial?.bar }}\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parsers partial blocks', function() {
|
it('parsers partial blocks', function() {
|
||||||
equals(astFor('{{#> foo}}bar{{/foo}}'), '{{> PARTIAL BLOCK:foo PROGRAM:\n CONTENT[ \'bar\' ]\n }}\n');
|
equals(
|
||||||
|
astFor('{{#> foo}}bar{{/foo}}'),
|
||||||
|
"{{> PARTIAL BLOCK:foo PROGRAM:\n CONTENT[ 'bar' ]\n }}\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should handle parser block mismatch', function() {
|
it('should handle parser block mismatch', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('{{#> goodbyes}}{{/hellos}}');
|
astFor('{{#> goodbyes}}{{/hellos}}');
|
||||||
}, Error, (/goodbyes doesn't match hellos/));
|
},
|
||||||
|
Error,
|
||||||
|
/goodbyes doesn't match hellos/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('parsers partial blocks with arguments', function() {
|
it('parsers partial blocks with arguments', function() {
|
||||||
equals(astFor('{{#> foo context hash=value}}bar{{/foo}}'), '{{> PARTIAL BLOCK:foo PATH:context HASH{hash=PATH:value} PROGRAM:\n CONTENT[ \'bar\' ]\n }}\n');
|
equals(
|
||||||
|
astFor('{{#> foo context hash=value}}bar{{/foo}}'),
|
||||||
|
"{{> PARTIAL BLOCK:foo PATH:context HASH{hash=PATH:value} PROGRAM:\n CONTENT[ 'bar' ]\n }}\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses a comment', function() {
|
it('parses a comment', function() {
|
||||||
equals(astFor('{{! this is a comment }}'), "{{! ' this is a comment ' }}\n");
|
equals(
|
||||||
|
astFor('{{! this is a comment }}'),
|
||||||
|
"{{! ' this is a comment ' }}\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses a multi-line comment', function() {
|
it('parses a multi-line comment', function() {
|
||||||
equals(astFor('{{!\nthis is a multi-line comment\n}}'), "{{! '\nthis is a multi-line comment\n' }}\n");
|
equals(
|
||||||
|
astFor('{{!\nthis is a multi-line comment\n}}'),
|
||||||
|
"{{! '\nthis is a multi-line comment\n' }}\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses an inverse section', function() {
|
it('parses an inverse section', function() {
|
||||||
equals(astFor('{{#foo}} bar {{^}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
equals(
|
||||||
|
astFor('{{#foo}} bar {{^}} baz {{/foo}}'),
|
||||||
|
"BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses an inverse (else-style) section', function() {
|
it('parses an inverse (else-style) section', function() {
|
||||||
equals(astFor('{{#foo}} bar {{else}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
equals(
|
||||||
|
astFor('{{#foo}} bar {{else}} baz {{/foo}}'),
|
||||||
|
"BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses multiple inverse sections', function() {
|
it('parses multiple inverse sections', function() {
|
||||||
equals(astFor('{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n BLOCK:\n PATH:if [PATH:bar]\n PROGRAM:\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
equals(
|
||||||
|
astFor('{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}'),
|
||||||
|
"BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n BLOCK:\n PATH:if [PATH:bar]\n PROGRAM:\n {{^}}\n CONTENT[ ' baz ' ]\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses empty blocks', function() {
|
it('parses empty blocks', function() {
|
||||||
@@ -156,31 +223,52 @@ describe('parser', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('parses empty blocks with empty inverse section', function() {
|
it('parses empty blocks with empty inverse section', function() {
|
||||||
equals(astFor('{{#foo}}{{^}}{{/foo}}'), 'BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n');
|
equals(
|
||||||
|
astFor('{{#foo}}{{^}}{{/foo}}'),
|
||||||
|
'BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses empty blocks with empty inverse (else-style) section', function() {
|
it('parses empty blocks with empty inverse (else-style) section', function() {
|
||||||
equals(astFor('{{#foo}}{{else}}{{/foo}}'), 'BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n');
|
equals(
|
||||||
|
astFor('{{#foo}}{{else}}{{/foo}}'),
|
||||||
|
'BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses non-empty blocks with empty inverse section', function() {
|
it('parses non-empty blocks with empty inverse section', function() {
|
||||||
equals(astFor('{{#foo}} bar {{^}}{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
|
equals(
|
||||||
|
astFor('{{#foo}} bar {{^}}{{/foo}}'),
|
||||||
|
"BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses non-empty blocks with empty inverse (else-style) section', function() {
|
it('parses non-empty blocks with empty inverse (else-style) section', function() {
|
||||||
equals(astFor('{{#foo}} bar {{else}}{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
|
equals(
|
||||||
|
astFor('{{#foo}} bar {{else}}{{/foo}}'),
|
||||||
|
"BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses empty blocks with non-empty inverse section', function() {
|
it('parses empty blocks with non-empty inverse section', function() {
|
||||||
equals(astFor('{{#foo}}{{^}} bar {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
|
equals(
|
||||||
|
astFor('{{#foo}}{{^}} bar {{/foo}}'),
|
||||||
|
"BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses empty blocks with non-empty inverse (else-style) section', function() {
|
it('parses empty blocks with non-empty inverse (else-style) section', function() {
|
||||||
equals(astFor('{{#foo}}{{else}} bar {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
|
equals(
|
||||||
|
astFor('{{#foo}}{{else}} bar {{/foo}}'),
|
||||||
|
"BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses a standalone inverse section', function() {
|
it('parses a standalone inverse section', function() {
|
||||||
equals(astFor('{{^foo}}bar{{/foo}}'), "BLOCK:\n PATH:foo []\n {{^}}\n CONTENT[ 'bar' ]\n");
|
equals(
|
||||||
|
astFor('{{^foo}}bar{{/foo}}'),
|
||||||
|
"BLOCK:\n PATH:foo []\n {{^}}\n CONTENT[ 'bar' ]\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('throws on old inverse section', function() {
|
it('throws on old inverse section', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(function() {
|
||||||
@@ -189,105 +277,179 @@ describe('parser', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('parses block with block params', function() {
|
it('parses block with block params', function() {
|
||||||
equals(astFor('{{#foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
equals(
|
||||||
|
astFor('{{#foo as |bar baz|}}content{{/foo}}'),
|
||||||
|
"BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses inverse block with block params', function() {
|
it('parses inverse block with block params', function() {
|
||||||
equals(astFor('{{^foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n {{^}}\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
equals(
|
||||||
|
astFor('{{^foo as |bar baz|}}content{{/foo}}'),
|
||||||
|
"BLOCK:\n PATH:foo []\n {{^}}\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('parses chained inverse block with block params', function() {
|
it('parses chained inverse block with block params', function() {
|
||||||
equals(astFor('{{#foo}}{{else foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
equals(
|
||||||
|
astFor('{{#foo}}{{else foo as |bar baz|}}content{{/foo}}'),
|
||||||
|
"BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('raises if there\'s a Parse error', function() {
|
it("raises if there's a Parse error", function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('foo{{^}}bar');
|
astFor('foo{{^}}bar');
|
||||||
}, Error, /Parse error on line 1/);
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
/Parse error on line 1/
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('{{foo}');
|
astFor('{{foo}');
|
||||||
}, Error, /Parse error on line 1/);
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
/Parse error on line 1/
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('{{foo &}}');
|
astFor('{{foo &}}');
|
||||||
}, Error, /Parse error on line 1/);
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
/Parse error on line 1/
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('{{#goodbyes}}{{/hellos}}');
|
astFor('{{#goodbyes}}{{/hellos}}');
|
||||||
}, Error, /goodbyes doesn't match hellos/);
|
},
|
||||||
|
Error,
|
||||||
|
/goodbyes doesn't match hellos/
|
||||||
|
);
|
||||||
|
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('{{{{goodbyes}}}} {{{{/hellos}}}}');
|
astFor('{{{{goodbyes}}}} {{{{/hellos}}}}');
|
||||||
}, Error, /goodbyes doesn't match hellos/);
|
},
|
||||||
|
Error,
|
||||||
|
/goodbyes doesn't match hellos/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle invalid paths', function() {
|
it('should handle invalid paths', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('{{foo/../bar}}');
|
astFor('{{foo/../bar}}');
|
||||||
}, Error, /Invalid path: foo\/\.\. - 1:2/);
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
/Invalid path: foo\/\.\. - 1:2/
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('{{foo/./bar}}');
|
astFor('{{foo/./bar}}');
|
||||||
}, Error, /Invalid path: foo\/\. - 1:2/);
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
/Invalid path: foo\/\. - 1:2/
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('{{foo/this/bar}}');
|
astFor('{{foo/this/bar}}');
|
||||||
}, Error, /Invalid path: foo\/this - 1:2/);
|
},
|
||||||
|
Error,
|
||||||
|
/Invalid path: foo\/this - 1:2/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('knows how to report the correct line number in errors', function() {
|
it('knows how to report the correct line number in errors', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('hello\nmy\n{{foo}');
|
astFor('hello\nmy\n{{foo}');
|
||||||
}, Error, /Parse error on line 3/);
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
/Parse error on line 3/
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('hello\n\nmy\n\n{{foo}');
|
astFor('hello\n\nmy\n\n{{foo}');
|
||||||
}, Error, /Parse error on line 5/);
|
},
|
||||||
|
Error,
|
||||||
|
/Parse error on line 5/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('knows how to report the correct line number in errors when the first character is a newline', function() {
|
it('knows how to report the correct line number in errors when the first character is a newline', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('\n\nhello\n\nmy\n\n{{foo}');
|
astFor('\n\nhello\n\nmy\n\n{{foo}');
|
||||||
}, Error, /Parse error on line 7/);
|
},
|
||||||
|
Error,
|
||||||
|
/Parse error on line 7/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('externally compiled AST', function() {
|
describe('externally compiled AST', function() {
|
||||||
it('can pass through an already-compiled AST', function() {
|
it('can pass through an already-compiled AST', function() {
|
||||||
equals(astFor({
|
equals(
|
||||||
|
astFor({
|
||||||
type: 'Program',
|
type: 'Program',
|
||||||
body: [{ type: 'ContentStatement', value: 'Hello' }]
|
body: [{ type: 'ContentStatement', value: 'Hello' }]
|
||||||
}), 'CONTENT[ \'Hello\' ]\n');
|
}),
|
||||||
|
"CONTENT[ 'Hello' ]\n"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('directives', function() {
|
describe('directives', function() {
|
||||||
it('should parse block directives', function() {
|
it('should parse block directives', function() {
|
||||||
equals(astFor('{{#* foo}}{{/foo}}'), 'DIRECTIVE BLOCK:\n PATH:foo []\n PROGRAM:\n');
|
equals(
|
||||||
|
astFor('{{#* foo}}{{/foo}}'),
|
||||||
|
'DIRECTIVE BLOCK:\n PATH:foo []\n PROGRAM:\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should parse directives', function() {
|
it('should parse directives', function() {
|
||||||
equals(astFor('{{* foo}}'), '{{ DIRECTIVE PATH:foo [] }}\n');
|
equals(astFor('{{* foo}}'), '{{ DIRECTIVE PATH:foo [] }}\n');
|
||||||
});
|
});
|
||||||
it('should fail if directives have inverse', function() {
|
it('should fail if directives have inverse', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
astFor('{{#* foo}}{{^}}{{/foo}}');
|
astFor('{{#* foo}}{{^}}{{/foo}}');
|
||||||
}, Error, /Unexpected inverse/);
|
},
|
||||||
|
Error,
|
||||||
|
/Unexpected inverse/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GH1024 - should track program location properly', function() {
|
it('GH1024 - should track program location properly', function() {
|
||||||
var p = Handlebars.parse('\n'
|
var p = Handlebars.parse(
|
||||||
+ ' {{#if foo}}\n'
|
'\n' +
|
||||||
+ ' {{bar}}\n'
|
' {{#if foo}}\n' +
|
||||||
+ ' {{else}} {{baz}}\n'
|
' {{bar}}\n' +
|
||||||
+ '\n'
|
' {{else}} {{baz}}\n' +
|
||||||
+ ' {{/if}}\n'
|
'\n' +
|
||||||
+ ' ');
|
' {{/if}}\n' +
|
||||||
|
' '
|
||||||
|
);
|
||||||
|
|
||||||
// We really need a deep equals but for now this should be stable...
|
// We really need a deep equals but for now this should be stable...
|
||||||
equals(JSON.stringify(p.loc), JSON.stringify({
|
equals(
|
||||||
|
JSON.stringify(p.loc),
|
||||||
|
JSON.stringify({
|
||||||
start: { line: 1, column: 0 },
|
start: { line: 1, column: 0 },
|
||||||
end: { line: 7, column: 4 }
|
end: { line: 7, column: 4 }
|
||||||
}));
|
})
|
||||||
equals(JSON.stringify(p.body[1].program.loc), JSON.stringify({
|
);
|
||||||
|
equals(
|
||||||
|
JSON.stringify(p.body[1].program.loc),
|
||||||
|
JSON.stringify({
|
||||||
start: { line: 2, column: 13 },
|
start: { line: 2, column: 13 },
|
||||||
end: { line: 4, column: 7 }
|
end: { line: 4, column: 7 }
|
||||||
}));
|
})
|
||||||
equals(JSON.stringify(p.body[1].inverse.loc), JSON.stringify({
|
);
|
||||||
|
equals(
|
||||||
|
JSON.stringify(p.body[1].inverse.loc),
|
||||||
|
JSON.stringify({
|
||||||
start: { line: 4, column: 15 },
|
start: { line: 4, column: 15 },
|
||||||
end: { line: 6, column: 5 }
|
end: { line: 6, column: 5 }
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+447
-105
@@ -2,115 +2,224 @@ 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 = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
|
dudes: [
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial},, false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }],
|
||||||
|
true,
|
||||||
|
'Dudes: Yehuda (http://yehuda) Alan (http://alan) '
|
||||||
|
);
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }, , false],
|
||||||
|
true,
|
||||||
|
'Dudes: Yehuda (http://yehuda) Alan (http://alan) '
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
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 = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
var helpers = {
|
var helpers = {
|
||||||
partial: function() {
|
partial: function() {
|
||||||
return 'dude';
|
return 'dude';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
shouldCompileToWithPartials(string, [hash, helpers, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
|
shouldCompileToWithPartials(
|
||||||
shouldCompileToWithPartials(string, [hash, helpers, {dude: partial},, false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
|
string,
|
||||||
|
[hash, helpers, { dude: partial }],
|
||||||
|
true,
|
||||||
|
'Dudes: Yehuda (http://yehuda) Alan (http://alan) '
|
||||||
|
);
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, helpers, { dude: partial }, , false],
|
||||||
|
true,
|
||||||
|
'Dudes: Yehuda (http://yehuda) Alan (http://alan) '
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('failing dynamic partials', function() {
|
it('failing 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 = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
var helpers = {
|
var helpers = {
|
||||||
partial: function() {
|
partial: function() {
|
||||||
return 'missing';
|
return 'missing';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
shouldCompileToWithPartials(string, [hash, helpers, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
|
function() {
|
||||||
}, Handlebars.Exception, 'The partial missing could not be found');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, helpers, { dude: partial }],
|
||||||
|
true,
|
||||||
|
'Dudes: Yehuda (http://yehuda) Alan (http://alan) '
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'The partial missing could not be found'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('partials with context', function() {
|
it('partials with context', function() {
|
||||||
var string = 'Dudes: {{>dude dudes}}';
|
var string = 'Dudes: {{>dude dudes}}';
|
||||||
var partial = '{{#this}}{{name}} ({{url}}) {{/this}}';
|
var partial = '{{#this}}{{name}} ({{url}}) {{/this}}';
|
||||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ',
|
dudes: [
|
||||||
'Partials can be passed a context');
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }],
|
||||||
|
true,
|
||||||
|
'Dudes: Yehuda (http://yehuda) Alan (http://alan) ',
|
||||||
|
'Partials can be passed a context'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('partials with no context', function() {
|
it('partials with no context', function() {
|
||||||
var partial = '{{name}} ({{url}}) ';
|
var partial = '{{name}} ({{url}}) ';
|
||||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
'Dudes: {{#dudes}}{{>dude}}{{/dudes}}',
|
'Dudes: {{#dudes}}{{>dude}}{{/dudes}}',
|
||||||
[hash, {}, { dude: partial }, { explicitPartialContext: true }],
|
[hash, {}, { dude: partial }, { explicitPartialContext: true }],
|
||||||
true,
|
true,
|
||||||
'Dudes: () () ');
|
'Dudes: () () '
|
||||||
|
);
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
'Dudes: {{#dudes}}{{>dude name="foo"}}{{/dudes}}',
|
'Dudes: {{#dudes}}{{>dude name="foo"}}{{/dudes}}',
|
||||||
[hash, {}, { dude: partial }, { explicitPartialContext: true }],
|
[hash, {}, { dude: partial }, { explicitPartialContext: true }],
|
||||||
true,
|
true,
|
||||||
'Dudes: foo () foo () ');
|
'Dudes: foo () foo () '
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('partials with string context', function() {
|
it('partials with string context', function() {
|
||||||
var string = 'Dudes: {{>dude "dudes"}}';
|
var string = 'Dudes: {{>dude "dudes"}}';
|
||||||
var partial = '{{.}}';
|
var partial = '{{.}}';
|
||||||
var hash = {};
|
var hash = {};
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: dudes');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }],
|
||||||
|
true,
|
||||||
|
'Dudes: dudes'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('partials with undefined context', function() {
|
it('partials with undefined context', function() {
|
||||||
var string = 'Dudes: {{>dude dudes}}';
|
var string = 'Dudes: {{>dude dudes}}';
|
||||||
var partial = '{{foo}} Empty';
|
var partial = '{{foo}} Empty';
|
||||||
var hash = {};
|
var hash = {};
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: Empty');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }],
|
||||||
|
true,
|
||||||
|
'Dudes: Empty'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('partials with duplicate parameters', function() {
|
it('partials with duplicate parameters', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
CompilerContext.compile('Dudes: {{>dude dudes foo bar=baz}}');
|
CompilerContext.compile('Dudes: {{>dude dudes foo bar=baz}}');
|
||||||
}, Error, 'Unsupported number of partial arguments: 2 - 1:7');
|
},
|
||||||
|
Error,
|
||||||
|
'Unsupported number of partial arguments: 2 - 1:7'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('partials with parameters', function() {
|
it('partials with parameters', function() {
|
||||||
var string = 'Dudes: {{#dudes}}{{> dude others=..}}{{/dudes}}';
|
var string = 'Dudes: {{#dudes}}{{> dude others=..}}{{/dudes}}';
|
||||||
var partial = '{{others.foo}}{{name}} ({{url}}) ';
|
var partial = '{{others.foo}}{{name}} ({{url}}) ';
|
||||||
var hash = {foo: 'bar', dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: barYehuda (http://yehuda) barAlan (http://alan) ',
|
foo: 'bar',
|
||||||
'Basic partials output based on current context.');
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }],
|
||||||
|
true,
|
||||||
|
'Dudes: barYehuda (http://yehuda) barAlan (http://alan) ',
|
||||||
|
'Basic partials output based on current context.'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('partial in a partial', function() {
|
it('partial in a partial', function() {
|
||||||
var string = 'Dudes: {{#dudes}}{{>dude}}{{/dudes}}';
|
var string = 'Dudes: {{#dudes}}{{>dude}}{{/dudes}}';
|
||||||
var dude = '{{name}} {{> url}} ';
|
var dude = '{{name}} {{> url}} ';
|
||||||
var url = '<a href="{{url}}">{{url}}</a>';
|
var url = '<a href="{{url}}">{{url}}</a>';
|
||||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}], true, 'Dudes: Yehuda <a href="http://yehuda">http://yehuda</a> Alan <a href="http://alan">http://alan</a> ', 'Partials are rendered inside of other partials');
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: dude, url: url }],
|
||||||
|
true,
|
||||||
|
'Dudes: Yehuda <a href="http://yehuda">http://yehuda</a> Alan <a href="http://alan">http://alan</a> ',
|
||||||
|
'Partials are rendered inside of other partials'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rendering undefined partial throws an exception', function() {
|
it('rendering undefined partial throws an exception', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
var template = CompilerContext.compile('{{> whatever}}');
|
var template = CompilerContext.compile('{{> whatever}}');
|
||||||
template();
|
template();
|
||||||
}, Handlebars.Exception, 'The partial whatever could not be found');
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'The partial whatever could not be found'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registering undefined partial throws an exception', function() {
|
it('registering undefined partial throws an exception', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
var undef;
|
var undef;
|
||||||
handlebarsEnv.registerPartial('undefined_test', undef);
|
handlebarsEnv.registerPartial('undefined_test', undef);
|
||||||
}, Handlebars.Exception, 'Attempting to register a partial called "undefined_test" as undefined');
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'Attempting to register a partial called "undefined_test" as undefined'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rendering template partial in vm mode throws an exception', function() {
|
it('rendering template partial in vm mode throws an exception', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
var template = CompilerContext.compile('{{> whatever}}');
|
var template = CompilerContext.compile('{{> whatever}}');
|
||||||
template();
|
template();
|
||||||
}, Handlebars.Exception, 'The partial whatever could not be found');
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'The partial whatever could not be found'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rendering function partial in vm mode', function() {
|
it('rendering function partial in vm mode', function() {
|
||||||
@@ -118,30 +227,57 @@ describe('partials', function() {
|
|||||||
function partial(context) {
|
function partial(context) {
|
||||||
return context.name + ' (' + context.url + ') ';
|
return context.name + ' (' + context.url + ') ';
|
||||||
}
|
}
|
||||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileTo(string, [hash, {}, {dude: partial}], 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ',
|
dudes: [
|
||||||
'Function partials output based in VM.');
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }],
|
||||||
|
'Dudes: Yehuda (http://yehuda) Alan (http://alan) ',
|
||||||
|
'Function partials output based in VM.'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GH-14: a partial preceding a selector', function() {
|
it('GH-14: a partial preceding a selector', function() {
|
||||||
var string = 'Dudes: {{>dude}} {{anotherDude}}';
|
var string = 'Dudes: {{>dude}} {{anotherDude}}';
|
||||||
var dude = '{{name}}';
|
var dude = '{{name}}';
|
||||||
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: dude}], true, 'Dudes: Jeepers Creepers', 'Regular selectors can follow a partial');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: dude }],
|
||||||
|
true,
|
||||||
|
'Dudes: Jeepers Creepers',
|
||||||
|
'Regular selectors can follow a partial'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Partials with slash paths', function() {
|
it('Partials with slash paths', function() {
|
||||||
var string = 'Dudes: {{> shared/dude}}';
|
var string = 'Dudes: {{> shared/dude}}';
|
||||||
var dude = '{{name}}';
|
var dude = '{{name}}';
|
||||||
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { 'shared/dude': dude }],
|
||||||
|
true,
|
||||||
|
'Dudes: Jeepers',
|
||||||
|
'Partials can use literal paths'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Partials with slash and point paths', function() {
|
it('Partials with slash and point paths', function() {
|
||||||
var string = 'Dudes: {{> shared/dude.thing}}';
|
var string = 'Dudes: {{> shared/dude.thing}}';
|
||||||
var dude = '{{name}}';
|
var dude = '{{name}}';
|
||||||
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude.thing': dude}], true, 'Dudes: Jeepers', 'Partials can use literal with points in paths');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { 'shared/dude.thing': dude }],
|
||||||
|
true,
|
||||||
|
'Dudes: Jeepers',
|
||||||
|
'Partials can use literal with points in paths'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Global Partials', function() {
|
it('Global Partials', function() {
|
||||||
@@ -150,7 +286,13 @@ describe('partials', function() {
|
|||||||
var string = 'Dudes: {{> shared/dude}} {{> globalTest}}';
|
var string = 'Dudes: {{> shared/dude}} {{> globalTest}}';
|
||||||
var dude = '{{name}}';
|
var dude = '{{name}}';
|
||||||
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude': dude}], true, 'Dudes: Jeepers Creepers', 'Partials can use globals or passed');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { 'shared/dude': dude }],
|
||||||
|
true,
|
||||||
|
'Dudes: Jeepers Creepers',
|
||||||
|
'Partials can use globals or passed'
|
||||||
|
);
|
||||||
|
|
||||||
handlebarsEnv.unregisterPartial('globalTest');
|
handlebarsEnv.unregisterPartial('globalTest');
|
||||||
equals(handlebarsEnv.partials.globalTest, undefined);
|
equals(handlebarsEnv.partials.globalTest, undefined);
|
||||||
@@ -164,50 +306,94 @@ describe('partials', function() {
|
|||||||
|
|
||||||
var string = 'Dudes: {{> shared/dude}} {{> globalTest}}';
|
var string = 'Dudes: {{> shared/dude}} {{> globalTest}}';
|
||||||
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
||||||
shouldCompileToWithPartials(string, [hash], true, 'Dudes: Jeepers Creepers', 'Partials can use globals or passed');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash],
|
||||||
|
true,
|
||||||
|
'Dudes: Jeepers Creepers',
|
||||||
|
'Partials can use globals or passed'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Partials with integer path', function() {
|
it('Partials with integer path', function() {
|
||||||
var string = 'Dudes: {{> 404}}';
|
var string = 'Dudes: {{> 404}}';
|
||||||
var dude = '{{name}}';
|
var dude = '{{name}}';
|
||||||
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {404: dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { 404: dude }],
|
||||||
|
true,
|
||||||
|
'Dudes: Jeepers',
|
||||||
|
'Partials can use literal paths'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Partials with complex path', function() {
|
it('Partials with complex path', function() {
|
||||||
var string = 'Dudes: {{> 404/asdf?.bar}}';
|
var string = 'Dudes: {{> 404/asdf?.bar}}';
|
||||||
var dude = '{{name}}';
|
var dude = '{{name}}';
|
||||||
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {'404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { '404/asdf?.bar': dude }],
|
||||||
|
true,
|
||||||
|
'Dudes: Jeepers',
|
||||||
|
'Partials can use literal paths'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Partials with escaped', function() {
|
it('Partials with escaped', function() {
|
||||||
var string = 'Dudes: {{> [+404/asdf?.bar]}}';
|
var string = 'Dudes: {{> [+404/asdf?.bar]}}';
|
||||||
var dude = '{{name}}';
|
var dude = '{{name}}';
|
||||||
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { '+404/asdf?.bar': dude }],
|
||||||
|
true,
|
||||||
|
'Dudes: Jeepers',
|
||||||
|
'Partials can use literal paths'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Partials with string', function() {
|
it('Partials with string', function() {
|
||||||
var string = 'Dudes: {{> \'+404/asdf?.bar\'}}';
|
var string = "Dudes: {{> '+404/asdf?.bar'}}";
|
||||||
var dude = '{{name}}';
|
var dude = '{{name}}';
|
||||||
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
var hash = { name: 'Jeepers', anotherDude: 'Creepers' };
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { '+404/asdf?.bar': dude }],
|
||||||
|
true,
|
||||||
|
'Dudes: Jeepers',
|
||||||
|
'Partials can use literal paths'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle empty partial', function() {
|
it('should handle empty partial', function() {
|
||||||
var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
|
var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
|
||||||
var partial = '';
|
var partial = '';
|
||||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: ');
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }],
|
||||||
|
true,
|
||||||
|
'Dudes: '
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throw on missing partial', function() {
|
it('throw on missing partial', function() {
|
||||||
var compile = handlebarsEnv.compile;
|
var compile = handlebarsEnv.compile;
|
||||||
handlebarsEnv.compile = undefined;
|
handlebarsEnv.compile = undefined;
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
shouldCompileTo('{{> dude}}', [{}, {}, { dude: 'fail' }], '');
|
shouldCompileTo('{{> dude}}', [{}, {}, { dude: 'fail' }], '');
|
||||||
}, Error, /The partial dude could not be compiled/);
|
},
|
||||||
|
Error,
|
||||||
|
/The partial dude could not be compiled/
|
||||||
|
);
|
||||||
handlebarsEnv.compile = compile;
|
handlebarsEnv.compile = compile;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -217,21 +403,24 @@ describe('partials', function() {
|
|||||||
'{{#> dude}}success{{/dude}}',
|
'{{#> dude}}success{{/dude}}',
|
||||||
[{}, {}, {}],
|
[{}, {}, {}],
|
||||||
true,
|
true,
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should execute default block with proper context', function() {
|
it('should execute default block with proper context', function() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
'{{#> dude context}}{{value}}{{/dude}}',
|
'{{#> dude context}}{{value}}{{/dude}}',
|
||||||
[{ context: { value: 'success' } }, {}, {}],
|
[{ context: { value: 'success' } }, {}, {}],
|
||||||
true,
|
true,
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should propagate block parameters to default block', function() {
|
it('should propagate block parameters to default block', function() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
'{{#with context as |me|}}{{#> dude}}{{me.value}}{{/dude}}{{/with}}',
|
'{{#with context as |me|}}{{#> dude}}{{me.value}}{{/dude}}{{/with}}',
|
||||||
[{ context: { value: 'success' } }, {}, {}],
|
[{ context: { value: 'success' } }, {}, {}],
|
||||||
true,
|
true,
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not use partial block if partial exists', function() {
|
it('should not use partial block if partial exists', function() {
|
||||||
@@ -239,7 +428,8 @@ describe('partials', function() {
|
|||||||
'{{#> dude}}fail{{/dude}}',
|
'{{#> dude}}fail{{/dude}}',
|
||||||
[{}, {}, { dude: 'success' }],
|
[{}, {}, { dude: 'success' }],
|
||||||
true,
|
true,
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render block from partial', function() {
|
it('should render block from partial', function() {
|
||||||
@@ -247,29 +437,44 @@ describe('partials', function() {
|
|||||||
'{{#> dude}}success{{/dude}}',
|
'{{#> dude}}success{{/dude}}',
|
||||||
[{}, {}, { dude: '{{> @partial-block }}' }],
|
[{}, {}, { dude: '{{> @partial-block }}' }],
|
||||||
true,
|
true,
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should be able to render the partial-block twice', function() {
|
it('should be able to render the partial-block twice', function() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
'{{#> dude}}success{{/dude}}',
|
'{{#> dude}}success{{/dude}}',
|
||||||
[{}, {}, { dude: '{{> @partial-block }} {{> @partial-block }}' }],
|
[{}, {}, { dude: '{{> @partial-block }} {{> @partial-block }}' }],
|
||||||
true,
|
true,
|
||||||
'success success');
|
'success success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should render block from partial with context', function() {
|
it('should render block from partial with context', function() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
'{{#> dude}}{{value}}{{/dude}}',
|
'{{#> dude}}{{value}}{{/dude}}',
|
||||||
[{context: {value: 'success'}}, {}, {dude: '{{#with context}}{{> @partial-block }}{{/with}}'}],
|
[
|
||||||
|
{ context: { value: 'success' } },
|
||||||
|
{},
|
||||||
|
{ dude: '{{#with context}}{{> @partial-block }}{{/with}}' }
|
||||||
|
],
|
||||||
true,
|
true,
|
||||||
'success');
|
'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() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
'{{#> dude}}in-block: {{@root/value}}{{/dude}}',
|
'{{#> dude}}in-block: {{@root/value}}{{/dude}}',
|
||||||
[{value: 'success'}, {}, {dude: '<code>before-block: {{@root/value}} {{> @partial-block }}</code>'}],
|
[
|
||||||
|
{ value: 'success' },
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
dude:
|
||||||
|
'<code>before-block: {{@root/value}} {{> @partial-block }}</code>'
|
||||||
|
}
|
||||||
|
],
|
||||||
true,
|
true,
|
||||||
'<code>before-block: success in-block: success</code>');
|
'<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() {
|
||||||
@@ -279,11 +484,13 @@ describe('partials', function() {
|
|||||||
{ value: ['a', 'b', 'c'] },
|
{ value: ['a', 'b', 'c'] },
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
list: '<list>{{#each .}}<item>{{> @partial-block}}</item>{{/each}}</list>'
|
list:
|
||||||
|
'<list>{{#each .}}<item>{{> @partial-block}}</item>{{/each}}</list>'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
'<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() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
@@ -292,25 +499,37 @@ describe('partials', function() {
|
|||||||
{ context: { value: 'success' } },
|
{ context: { value: 'success' } },
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
dude: '{{#with context}}{{> @partial-block }} {{> @partial-block }}{{/with}}'
|
dude:
|
||||||
|
'{{#with context}}{{> @partial-block }} {{> @partial-block }}{{/with}}'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
'success success');
|
'success success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should render block from partial with context', function() {
|
it('should render block from partial with context', function() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
'{{#> dude}}{{../context/value}}{{/dude}}',
|
'{{#> dude}}{{../context/value}}{{/dude}}',
|
||||||
[{context: {value: 'success'}}, {}, {dude: '{{#with context}}{{> @partial-block }}{{/with}}'}],
|
[
|
||||||
|
{ context: { value: 'success' } },
|
||||||
|
{},
|
||||||
|
{ dude: '{{#with context}}{{> @partial-block }}{{/with}}' }
|
||||||
|
],
|
||||||
true,
|
true,
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should render block from partial with block params', function() {
|
it('should render block from partial with block params', function() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
'{{#with context as |me|}}{{#> dude}}{{me.value}}{{/dude}}{{/with}}',
|
'{{#with context as |me|}}{{#> dude}}{{me.value}}{{/dude}}{{/with}}',
|
||||||
[{context: {value: 'success'}}, {}, {dude: '{{> @partial-block }}'}],
|
[
|
||||||
|
{ context: { value: 'success' } },
|
||||||
|
{},
|
||||||
|
{ dude: '{{> @partial-block }}' }
|
||||||
|
],
|
||||||
true,
|
true,
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should render nested partial blocks', function() {
|
it('should render nested partial blocks', function() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
@@ -319,12 +538,14 @@ describe('partials', function() {
|
|||||||
{ value: 'success' },
|
{ value: 'success' },
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
outer: '<outer>{{#> nested}}<outer-block>{{> @partial-block}}</outer-block>{{/nested}}</outer>',
|
outer:
|
||||||
|
'<outer>{{#> nested}}<outer-block>{{> @partial-block}}</outer-block>{{/nested}}</outer>',
|
||||||
nested: '<nested>{{> @partial-block}}</nested>'
|
nested: '<nested>{{> @partial-block}}</nested>'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
'<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() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
@@ -333,12 +554,14 @@ describe('partials', function() {
|
|||||||
{ value: 'success' },
|
{ value: 'success' },
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
outer: '<outer>{{#> nested}}<outer-block>{{> @partial-block}}</outer-block>{{/nested}}{{> @partial-block}}</outer>',
|
outer:
|
||||||
|
'<outer>{{#> nested}}<outer-block>{{> @partial-block}}</outer-block>{{/nested}}{{> @partial-block}}</outer>',
|
||||||
nested: '<nested>{{> @partial-block}}</nested>'
|
nested: '<nested>{{> @partial-block}}</nested>'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
'<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() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
@@ -347,12 +570,14 @@ describe('partials', function() {
|
|||||||
{ value: 'success' },
|
{ value: 'success' },
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
outer: '<outer>{{#> nested}}<outer-block>{{> @partial-block}} {{> @partial-block}}</outer-block>{{/nested}}{{> @partial-block}}+{{> @partial-block}}</outer>',
|
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>'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
'<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() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
@@ -361,38 +586,79 @@ describe('partials', function() {
|
|||||||
{ value: 'success' },
|
{ value: 'success' },
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
outer: '<outer>{{#> nested}}<outer-block>{{> @partial-block}} {{> @partial-block}}</outer-block>{{/nested}}</outer>',
|
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>'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
'<template><outer>' +
|
'<template><outer>' +
|
||||||
'<nested><outer-block>success success</outer-block><outer-block>success success</outer-block></nested>' +
|
'<nested><outer-block>success success</outer-block><outer-block>success success</outer-block></nested>' +
|
||||||
'</outer></template>');
|
'</outer></template>'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('inline partials', function() {
|
describe('inline partials', function() {
|
||||||
it('should define inline partials for template', function() {
|
it('should define inline partials for template', function() {
|
||||||
shouldCompileTo('{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}', {}, 'success');
|
shouldCompileTo(
|
||||||
|
'{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}',
|
||||||
|
{},
|
||||||
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should overwrite multiple partials in the same template', function() {
|
it('should overwrite multiple partials in the same template', function() {
|
||||||
shouldCompileTo('{{#*inline "myPartial"}}fail{{/inline}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}', {}, 'success');
|
shouldCompileTo(
|
||||||
|
'{{#*inline "myPartial"}}fail{{/inline}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}',
|
||||||
|
{},
|
||||||
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should define inline partials for block', function() {
|
it('should define inline partials for block', function() {
|
||||||
shouldCompileTo('{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}{{/with}}', {}, 'success');
|
shouldCompileTo(
|
||||||
shouldThrow(function() {
|
'{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}{{/with}}',
|
||||||
shouldCompileTo('{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{/with}}{{> myPartial}}', {}, 'success');
|
{},
|
||||||
}, Error, /myPartial could not/);
|
'success'
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{/with}}{{> myPartial}}',
|
||||||
|
{},
|
||||||
|
'success'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Error,
|
||||||
|
/myPartial could not/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should override global partials', function() {
|
it('should override global partials', function() {
|
||||||
shouldCompileTo('{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}', {hash: {}, partials: {myPartial: function() { return 'fail'; }}}, 'success');
|
shouldCompileTo(
|
||||||
|
'{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}',
|
||||||
|
{
|
||||||
|
hash: {},
|
||||||
|
partials: {
|
||||||
|
myPartial: function() {
|
||||||
|
return 'fail';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should override template partials', function() {
|
it('should override template partials', function() {
|
||||||
shouldCompileTo('{{#*inline "myPartial"}}fail{{/inline}}{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}{{/with}}', {}, 'success');
|
shouldCompileTo(
|
||||||
|
'{{#*inline "myPartial"}}fail{{/inline}}{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}{{/with}}',
|
||||||
|
{},
|
||||||
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should override partials down the entire stack', function() {
|
it('should override partials down the entire stack', function() {
|
||||||
shouldCompileTo('{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{#with .}}{{#with .}}{{> myPartial}}{{/with}}{{/with}}{{/with}}', {}, 'success');
|
shouldCompileTo(
|
||||||
|
'{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{#with .}}{{#with .}}{{> myPartial}}{{/with}}{{/with}}{{/with}}',
|
||||||
|
{},
|
||||||
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should define inline partials for partial call', function() {
|
it('should define inline partials for partial call', function() {
|
||||||
@@ -400,14 +666,16 @@ describe('partials', function() {
|
|||||||
'{{#*inline "myPartial"}}success{{/inline}}{{> dude}}',
|
'{{#*inline "myPartial"}}success{{/inline}}{{> dude}}',
|
||||||
[{}, {}, { dude: '{{> myPartial }}' }],
|
[{}, {}, { dude: '{{> myPartial }}' }],
|
||||||
true,
|
true,
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should define inline partials in partial block call', function() {
|
it('should define inline partials in partial block call', function() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
'{{#> dude}}{{#*inline "myPartial"}}success{{/inline}}{{/dude}}',
|
'{{#> dude}}{{#*inline "myPartial"}}success{{/inline}}{{/dude}}',
|
||||||
[{}, {}, { dude: '{{> myPartial }}' }],
|
[{}, {}, { dude: '{{> myPartial }}' }],
|
||||||
true,
|
true,
|
||||||
'success');
|
'success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should render nested inline partials', function() {
|
it('should render nested inline partials', function() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
@@ -416,7 +684,8 @@ describe('partials', function() {
|
|||||||
'{{#>outer}}{{value}}{{/outer}}',
|
'{{#>outer}}{{value}}{{/outer}}',
|
||||||
[{ value: 'success' }, {}, {}],
|
[{ value: 'success' }, {}, {}],
|
||||||
true,
|
true,
|
||||||
'<inner><outer-block>success</outer-block></inner>');
|
'<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() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
@@ -425,7 +694,8 @@ describe('partials', function() {
|
|||||||
'{{#>outer}}{{value}}{{/outer}}',
|
'{{#>outer}}{{value}}{{/outer}}',
|
||||||
[{ value: 'success' }, {}, {}],
|
[{ value: 'success' }, {}, {}],
|
||||||
true,
|
true,
|
||||||
'<inner><outer-block>success</outer-block></inner>success');
|
'<inner><outer-block>success</outer-block></inner>success'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should render nested inline partials (twice at each level)', function() {
|
it('should render nested inline partials (twice at each level)', function() {
|
||||||
shouldCompileToWithPartials(
|
shouldCompileToWithPartials(
|
||||||
@@ -434,7 +704,8 @@ describe('partials', function() {
|
|||||||
'{{#>outer}}{{value}}{{/outer}}',
|
'{{#>outer}}{{value}}{{/outer}}',
|
||||||
[{ value: 'success' }, {}, {}],
|
[{ value: 'success' }, {}, {}],
|
||||||
true,
|
true,
|
||||||
'<inner><outer-block>success success</outer-block><outer-block>success success</outer-block></inner>');
|
'<inner><outer-block>success success</outer-block><outer-block>success success</outer-block></inner>'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -451,25 +722,52 @@ describe('partials', function() {
|
|||||||
it('indented partials', function() {
|
it('indented partials', function() {
|
||||||
var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}';
|
var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}';
|
||||||
var dude = '{{name}}\n';
|
var dude = '{{name}}\n';
|
||||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: dude}], true,
|
dudes: [
|
||||||
'Dudes:\n Yehuda\n Alan\n');
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: dude }],
|
||||||
|
true,
|
||||||
|
'Dudes:\n Yehuda\n Alan\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('nested indented partials', function() {
|
it('nested indented partials', function() {
|
||||||
var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}';
|
var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}';
|
||||||
var dude = '{{name}}\n {{> url}}';
|
var dude = '{{name}}\n {{> url}}';
|
||||||
var url = '{{url}}!\n';
|
var url = '{{url}}!\n';
|
||||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}], true,
|
dudes: [
|
||||||
'Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n');
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: dude, url: url }],
|
||||||
|
true,
|
||||||
|
'Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('prevent nested indented partials', function() {
|
it('prevent nested indented partials', function() {
|
||||||
var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}';
|
var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}';
|
||||||
var dude = '{{name}}\n {{> url}}';
|
var dude = '{{name}}\n {{> url}}';
|
||||||
var url = '{{url}}!\n';
|
var url = '{{url}}!\n';
|
||||||
var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}, {preventIndent: true}], true,
|
dudes: [
|
||||||
'Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n');
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: dude, url: url }, { preventIndent: true }],
|
||||||
|
true,
|
||||||
|
'Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -477,26 +775,70 @@ describe('partials', function() {
|
|||||||
it('partials can access parents', function() {
|
it('partials can access parents', function() {
|
||||||
var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
|
var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
|
||||||
var partial = '{{name}} ({{url}}) {{root}} ';
|
var partial = '{{name}} ({{url}}) {{root}} ';
|
||||||
var hash = {root: 'yes', dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}, true], true, 'Dudes: Yehuda (http://yehuda) yes Alan (http://alan) yes ');
|
root: 'yes',
|
||||||
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }, true],
|
||||||
|
true,
|
||||||
|
'Dudes: Yehuda (http://yehuda) yes Alan (http://alan) yes '
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('partials can access parents with custom context', function() {
|
it('partials can access parents with custom context', function() {
|
||||||
var string = 'Dudes: {{#dudes}}{{> dude "test"}}{{/dudes}}';
|
var string = 'Dudes: {{#dudes}}{{> dude "test"}}{{/dudes}}';
|
||||||
var partial = '{{name}} ({{url}}) {{root}} ';
|
var partial = '{{name}} ({{url}}) {{root}} ';
|
||||||
var hash = {root: 'yes', dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}, true], true, 'Dudes: Yehuda (http://yehuda) yes Alan (http://alan) yes ');
|
root: 'yes',
|
||||||
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }, true],
|
||||||
|
true,
|
||||||
|
'Dudes: Yehuda (http://yehuda) yes Alan (http://alan) yes '
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('partials can access parents without data', function() {
|
it('partials can access parents without data', function() {
|
||||||
var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
|
var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
|
||||||
var partial = '{{name}} ({{url}}) {{root}} ';
|
var partial = '{{name}} ({{url}}) {{root}} ';
|
||||||
var hash = {root: 'yes', dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}, true, false], true, 'Dudes: Yehuda (http://yehuda) yes Alan (http://alan) yes ');
|
root: 'yes',
|
||||||
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }, true, false],
|
||||||
|
true,
|
||||||
|
'Dudes: Yehuda (http://yehuda) yes Alan (http://alan) yes '
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('partials inherit compat', function() {
|
it('partials inherit compat', function() {
|
||||||
var string = 'Dudes: {{> dude}}';
|
var string = 'Dudes: {{> dude}}';
|
||||||
var partial = '{{#dudes}}{{name}} ({{url}}) {{root}} {{/dudes}}';
|
var partial = '{{#dudes}}{{name}} ({{url}}) {{root}} {{/dudes}}';
|
||||||
var hash = {root: 'yes', dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
var hash = {
|
||||||
shouldCompileToWithPartials(string, [hash, {}, {dude: partial}, true], true, 'Dudes: Yehuda (http://yehuda) yes Alan (http://alan) yes ');
|
root: 'yes',
|
||||||
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[hash, {}, { dude: partial }, true],
|
||||||
|
true,
|
||||||
|
'Dudes: Yehuda (http://yehuda) yes Alan (http://alan) yes '
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+136
-43
@@ -14,16 +14,13 @@ describe('precompiler', function() {
|
|||||||
logFunction,
|
logFunction,
|
||||||
errorLog,
|
errorLog,
|
||||||
errorLogFunction,
|
errorLogFunction,
|
||||||
|
|
||||||
precompile,
|
precompile,
|
||||||
minify,
|
minify,
|
||||||
|
|
||||||
emptyTemplate = {
|
emptyTemplate = {
|
||||||
path: __dirname + '/artifacts/empty.handlebars',
|
path: __dirname + '/artifacts/empty.handlebars',
|
||||||
name: 'empty',
|
name: 'empty',
|
||||||
source: ''
|
source: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
file,
|
file,
|
||||||
content,
|
content,
|
||||||
writeFileSync;
|
writeFileSync;
|
||||||
@@ -91,97 +88,161 @@ describe('precompiler', function() {
|
|||||||
equals(log, Handlebars.VERSION);
|
equals(log, Handlebars.VERSION);
|
||||||
});
|
});
|
||||||
it('should throw if lacking templates', function() {
|
it('should throw if lacking templates', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Precompiler.cli({ templates: [] });
|
Precompiler.cli({ templates: [] });
|
||||||
}, Handlebars.Exception, 'Must define at least one template or directory.');
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'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(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Precompiler.cli({ templates: [__dirname], simple: true, min: true });
|
Precompiler.cli({ templates: [__dirname], simple: true, min: true });
|
||||||
}, Handlebars.Exception, 'Unable to minimize simple output');
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'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(function() {
|
shouldThrow(
|
||||||
Precompiler.cli({templates: [__dirname + '/artifacts/empty.handlebars', __dirname + '/artifacts/empty.handlebars'], simple: true});
|
function() {
|
||||||
}, Handlebars.Exception, 'Unable to output multiple templates in simple mode');
|
Precompiler.cli({
|
||||||
|
templates: [
|
||||||
|
__dirname + '/artifacts/empty.handlebars',
|
||||||
|
__dirname + '/artifacts/empty.handlebars'
|
||||||
|
],
|
||||||
|
simple: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'Unable to output multiple templates in simple mode'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should throw when missing name', function() {
|
it('should throw when missing name', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Precompiler.cli({ templates: [{ source: '' }], amd: true });
|
Precompiler.cli({ templates: [{ source: '' }], amd: true });
|
||||||
}, Handlebars.Exception, 'Name missing for template');
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'Name missing for template'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should throw when combining simple and directories', function() {
|
it('should throw when combining simple and directories', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Precompiler.cli({ hasDirectory: true, templates: [1], simple: true });
|
Precompiler.cli({ hasDirectory: true, templates: [1], simple: true });
|
||||||
}, Handlebars.Exception, 'Unable to output multiple templates in simple mode');
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'Unable to output multiple templates in simple mode'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should output simple templates', function() {
|
it('should output simple templates', function() {
|
||||||
Handlebars.precompile = function() { return 'simple'; };
|
Handlebars.precompile = function() {
|
||||||
|
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() { return 'simple'; };
|
Handlebars.precompile = function() {
|
||||||
|
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() { return 'amd'; };
|
Handlebars.precompile = function() {
|
||||||
|
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() { return 'amd'; };
|
Handlebars.precompile = function() {
|
||||||
Precompiler.cli({templates: [emptyTemplate, emptyTemplate], amd: true, namespace: 'foo'});
|
return 'amd';
|
||||||
|
};
|
||||||
|
Precompiler.cli({
|
||||||
|
templates: [emptyTemplate, emptyTemplate],
|
||||||
|
amd: true,
|
||||||
|
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() { return 'amd'; };
|
Handlebars.precompile = function() {
|
||||||
|
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() { return 'amd'; };
|
Handlebars.precompile = function() {
|
||||||
Precompiler.cli({templates: [emptyTemplate, emptyTemplate], amd: true, partial: true});
|
return 'amd';
|
||||||
|
};
|
||||||
|
Precompiler.cli({
|
||||||
|
templates: [emptyTemplate, emptyTemplate],
|
||||||
|
amd: 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() { return 'commonjs'; };
|
Handlebars.precompile = function() {
|
||||||
|
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) { equal(options.data, true); return 'simple'; };
|
Handlebars.precompile = function(data, options) {
|
||||||
|
equal(options.data, true);
|
||||||
|
return 'simple';
|
||||||
|
};
|
||||||
Precompiler.cli({ templates: [emptyTemplate], simple: true, data: true });
|
Precompiler.cli({ templates: [emptyTemplate], simple: true, data: true });
|
||||||
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) { equal(options.knownHelpers.foo, true); return 'simple'; };
|
Handlebars.precompile = function(data, options) {
|
||||||
|
equal(options.knownHelpers.foo, true);
|
||||||
|
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() { return 'simple'; };
|
Handlebars.precompile = function() {
|
||||||
Precompiler.cli({templates: [emptyTemplate], simple: true, output: 'file!'});
|
return 'simple';
|
||||||
|
};
|
||||||
|
Precompiler.cli({
|
||||||
|
templates: [emptyTemplate],
|
||||||
|
simple: true,
|
||||||
|
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() { return 'amd'; };
|
Handlebars.precompile = function() {
|
||||||
uglify.minify = function() { return {code: 'min'}; };
|
return 'amd';
|
||||||
|
};
|
||||||
|
uglify.minify = function() {
|
||||||
|
return { code: 'min' };
|
||||||
|
};
|
||||||
Precompiler.cli({ templates: [emptyTemplate], min: true });
|
Precompiler.cli({ templates: [emptyTemplate], min: true });
|
||||||
equal(log, 'min');
|
equal(log, 'min');
|
||||||
});
|
});
|
||||||
@@ -191,7 +252,9 @@ describe('precompiler', function() {
|
|||||||
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() { return 'amd'; };
|
Handlebars.precompile = function() {
|
||||||
|
return 'amd';
|
||||||
|
};
|
||||||
Precompiler.cli({ templates: [emptyTemplate], min: true });
|
Precompiler.cli({ templates: [emptyTemplate], min: true });
|
||||||
equal(/template\(amd\)/.test(log), true);
|
equal(/template\(amd\)/.test(log), true);
|
||||||
equal(/\n/.test(log), true);
|
equal(/\n/.test(log), true);
|
||||||
@@ -201,11 +264,17 @@ 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(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
var Precompiler = require('../dist/cjs/precompiler');
|
var Precompiler = require('../dist/cjs/precompiler');
|
||||||
Handlebars.precompile = function() { return 'amd'; };
|
Handlebars.precompile = function() {
|
||||||
|
return 'amd';
|
||||||
|
};
|
||||||
Precompiler.cli({ templates: [emptyTemplate], min: true });
|
Precompiler.cli({ templates: [emptyTemplate], min: true });
|
||||||
}, Error, 'Mock Error');
|
},
|
||||||
|
Error,
|
||||||
|
'Mock Error'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -217,7 +286,11 @@ describe('precompiler', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should output map', function() {
|
it('should output map', function() {
|
||||||
Precompiler.cli({templates: [emptyTemplate], min: true, map: 'foo.js.map'});
|
Precompiler.cli({
|
||||||
|
templates: [emptyTemplate],
|
||||||
|
min: true,
|
||||||
|
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);
|
||||||
@@ -231,29 +304,42 @@ describe('precompiler', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should enumerate directories by extension', function(done) {
|
it('should enumerate directories by extension', function(done) {
|
||||||
Precompiler.loadTemplates({files: [__dirname + '/artifacts'], extension: 'hbs'}, function(err, opts) {
|
Precompiler.loadTemplates(
|
||||||
|
{ files: [__dirname + '/artifacts'], extension: 'hbs' },
|
||||||
|
function(err, opts) {
|
||||||
equal(opts.templates.length, 1);
|
equal(opts.templates.length, 1);
|
||||||
equal(opts.templates[0].name, 'example_2');
|
equal(opts.templates[0].name, 'example_2');
|
||||||
done(err);
|
done(err);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should enumerate all templates by extension', function(done) {
|
it('should enumerate all templates by extension', function(done) {
|
||||||
Precompiler.loadTemplates({files: [__dirname + '/artifacts'], extension: 'handlebars'}, function(err, opts) {
|
Precompiler.loadTemplates(
|
||||||
|
{ files: [__dirname + '/artifacts'], extension: 'handlebars' },
|
||||||
|
function(err, opts) {
|
||||||
equal(opts.templates.length, 3);
|
equal(opts.templates.length, 3);
|
||||||
equal(opts.templates[0].name, 'bom');
|
equal(opts.templates[0].name, 'bom');
|
||||||
equal(opts.templates[1].name, 'empty');
|
equal(opts.templates[1].name, 'empty');
|
||||||
equal(opts.templates[2].name, 'example_1');
|
equal(opts.templates[2].name, 'example_1');
|
||||||
done(err);
|
done(err);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should handle regular expression characters in extensions', function(done) {
|
it('should handle regular expression characters in extensions', function(done) {
|
||||||
Precompiler.loadTemplates({files: [__dirname + '/artifacts'], extension: 'hb(s'}, function(err) {
|
Precompiler.loadTemplates(
|
||||||
|
{ files: [__dirname + '/artifacts'], extension: 'hb(s' },
|
||||||
|
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 = {files: [__dirname + '/artifacts/bom.handlebars'], extension: 'handlebars', bom: true};
|
var opts = {
|
||||||
|
files: [__dirname + '/artifacts/bom.handlebars'],
|
||||||
|
extension: 'handlebars',
|
||||||
|
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);
|
||||||
@@ -261,7 +347,11 @@ describe('precompiler', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should handle different root', function(done) {
|
it('should handle different root', function(done) {
|
||||||
var opts = {files: [__dirname + '/artifacts/empty.handlebars'], simple: true, root: 'foo/'};
|
var opts = {
|
||||||
|
files: [__dirname + '/artifacts/empty.handlebars'],
|
||||||
|
simple: true,
|
||||||
|
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);
|
||||||
@@ -299,7 +389,10 @@ describe('precompiler', function() {
|
|||||||
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(err.message, 'Number of names did not match the number of string inputs');
|
equal(
|
||||||
|
err.message,
|
||||||
|
'Number of names did not match the number of string inputs'
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+208
-93
@@ -1,50 +1,78 @@
|
|||||||
describe('Regressions', function() {
|
describe('Regressions', function() {
|
||||||
it('GH-94: Cannot read property of undefined', function() {
|
it('GH-94: Cannot read property of undefined', function() {
|
||||||
var data = {
|
var data = {
|
||||||
'books': [{
|
books: [
|
||||||
'title': 'The origin of species',
|
{
|
||||||
'author': {
|
title: 'The origin of species',
|
||||||
'name': 'Charles Darwin'
|
author: {
|
||||||
|
name: 'Charles Darwin'
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
'title': 'Lazarillo de Tormes'
|
{
|
||||||
}]
|
title: 'Lazarillo de Tormes'
|
||||||
|
}
|
||||||
|
]
|
||||||
};
|
};
|
||||||
var string = '{{#books}}{{title}}{{author.name}}{{/books}}';
|
var string = '{{#books}}{{title}}{{author.name}}{{/books}}';
|
||||||
shouldCompileTo(string, data, 'The origin of speciesCharles DarwinLazarillo de Tormes',
|
shouldCompileTo(
|
||||||
'Renders without an undefined property error');
|
string,
|
||||||
|
data,
|
||||||
|
'The origin of speciesCharles DarwinLazarillo de Tormes',
|
||||||
|
'Renders without an undefined property error'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("GH-150: Inverted sections print when they shouldn't", function() {
|
it("GH-150: Inverted sections print when they shouldn't", function() {
|
||||||
var string = '{{^set}}not set{{/set}} :: {{#set}}set{{/set}}';
|
var string = '{{^set}}not set{{/set}} :: {{#set}}set{{/set}}';
|
||||||
|
|
||||||
shouldCompileTo(string, {}, 'not set :: ', "inverted sections run when property isn't present in context");
|
shouldCompileTo(
|
||||||
shouldCompileTo(string, {set: undefined}, 'not set :: ', 'inverted sections run when property is undefined');
|
string,
|
||||||
shouldCompileTo(string, {set: false}, 'not set :: ', 'inverted sections run when property is false');
|
{},
|
||||||
shouldCompileTo(string, {set: true}, ' :: set', "inverted sections don't run when property is true");
|
'not set :: ',
|
||||||
|
"inverted sections run when property isn't present in context"
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ set: undefined },
|
||||||
|
'not set :: ',
|
||||||
|
'inverted sections run when property is undefined'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ set: false },
|
||||||
|
'not set :: ',
|
||||||
|
'inverted sections run when property is false'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ set: true },
|
||||||
|
' :: set',
|
||||||
|
"inverted sections don't run when property is true"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GH-158: Using array index twice, breaks the template', function() {
|
it('GH-158: Using array index twice, breaks the template', function() {
|
||||||
var string = '{{arr.[0]}}, {{arr.[1]}}';
|
var string = '{{arr.[0]}}, {{arr.[1]}}';
|
||||||
var data = { 'arr': [1, 2] };
|
var data = { arr: [1, 2] };
|
||||||
|
|
||||||
shouldCompileTo(string, data, '1, 2', 'it works as expected');
|
shouldCompileTo(string, data, '1, 2', 'it works as expected');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("bug reported by @fat where lambdas weren't being properly resolved", function() {
|
it("bug reported by @fat where lambdas weren't being properly resolved", function() {
|
||||||
var string = '<strong>This is a slightly more complicated {{thing}}.</strong>.\n'
|
var string =
|
||||||
+ '{{! Just ignore this business. }}\n'
|
'<strong>This is a slightly more complicated {{thing}}.</strong>.\n' +
|
||||||
+ 'Check this out:\n'
|
'{{! Just ignore this business. }}\n' +
|
||||||
+ '{{#hasThings}}\n'
|
'Check this out:\n' +
|
||||||
+ '<ul>\n'
|
'{{#hasThings}}\n' +
|
||||||
+ '{{#things}}\n'
|
'<ul>\n' +
|
||||||
+ '<li class={{className}}>{{word}}</li>\n'
|
'{{#things}}\n' +
|
||||||
+ '{{/things}}</ul>.\n'
|
'<li class={{className}}>{{word}}</li>\n' +
|
||||||
+ '{{/hasThings}}\n'
|
'{{/things}}</ul>.\n' +
|
||||||
+ '{{^hasThings}}\n'
|
'{{/hasThings}}\n' +
|
||||||
+ '\n'
|
'{{^hasThings}}\n' +
|
||||||
+ '<small>Nothing to check out...</small>\n'
|
'\n' +
|
||||||
+ '{{/hasThings}}';
|
'<small>Nothing to check out...</small>\n' +
|
||||||
|
'{{/hasThings}}';
|
||||||
var data = {
|
var data = {
|
||||||
thing: function() {
|
thing: function() {
|
||||||
return 'blah';
|
return 'blah';
|
||||||
@@ -59,13 +87,14 @@ describe('Regressions', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var output = '<strong>This is a slightly more complicated blah.</strong>.\n'
|
var output =
|
||||||
+ 'Check this out:\n'
|
'<strong>This is a slightly more complicated blah.</strong>.\n' +
|
||||||
+ '<ul>\n'
|
'Check this out:\n' +
|
||||||
+ '<li class=one>@fat</li>\n'
|
'<ul>\n' +
|
||||||
+ '<li class=two>@dhg</li>\n'
|
'<li class=one>@fat</li>\n' +
|
||||||
+ '<li class=three>@sayrer</li>\n'
|
'<li class=two>@dhg</li>\n' +
|
||||||
+ '</ul>.\n';
|
'<li class=three>@sayrer</li>\n' +
|
||||||
|
'</ul>.\n';
|
||||||
shouldCompileTo(string, data, output);
|
shouldCompileTo(string, data, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -75,19 +104,31 @@ describe('Regressions', function() {
|
|||||||
{ name: 'Jane Doe', location: { city: 'New York' } }
|
{ name: 'Jane Doe', location: { city: 'New York' } }
|
||||||
];
|
];
|
||||||
|
|
||||||
var template = CompilerContext.compile('{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}');
|
var template = CompilerContext.compile(
|
||||||
|
'{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}'
|
||||||
|
);
|
||||||
|
|
||||||
var result = template(context);
|
var result = template(context);
|
||||||
equals(result, 'John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe', 'It should output multiple times');
|
equals(
|
||||||
|
result,
|
||||||
|
'John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe',
|
||||||
|
'It should output multiple times'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GS-428: Nested if else rendering', function() {
|
it('GS-428: Nested if else rendering', function() {
|
||||||
var succeedingTemplate = '{{#inverse}} {{#blk}} Unexpected {{/blk}} {{else}} {{#blk}} Expected {{/blk}} {{/inverse}}';
|
var succeedingTemplate =
|
||||||
var failingTemplate = '{{#inverse}} {{#blk}} Unexpected {{/blk}} {{else}} {{#blk}} Expected {{/blk}} {{/inverse}}';
|
'{{#inverse}} {{#blk}} Unexpected {{/blk}} {{else}} {{#blk}} Expected {{/blk}} {{/inverse}}';
|
||||||
|
var failingTemplate =
|
||||||
|
'{{#inverse}} {{#blk}} Unexpected {{/blk}} {{else}} {{#blk}} Expected {{/blk}} {{/inverse}}';
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
blk: function(block) { return block.fn(''); },
|
blk: function(block) {
|
||||||
inverse: function(block) { return block.inverse(''); }
|
return block.fn('');
|
||||||
|
},
|
||||||
|
inverse: function(block) {
|
||||||
|
return block.inverse('');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldCompileTo(succeedingTemplate, [{}, helpers], ' Expected ');
|
shouldCompileTo(succeedingTemplate, [{}, helpers], ' Expected ');
|
||||||
@@ -104,11 +145,11 @@ describe('Regressions', function() {
|
|||||||
|
|
||||||
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;
|
||||||
|
|
||||||
shouldCompileTo('{{foo}}', { foo: 'bar' }, 'bar');
|
shouldCompileTo('{{foo}}', { foo: 'bar' }, 'bar');
|
||||||
|
|
||||||
delete Object.prototype[0xD834];
|
delete Object.prototype[0xd834];
|
||||||
/* eslint-enable no-extend-native */
|
/* eslint-enable no-extend-native */
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -123,25 +164,35 @@ describe('Regressions', function() {
|
|||||||
|
|
||||||
it('GH-676: Using array in escaping mustache fails', function() {
|
it('GH-676: Using array in escaping mustache fails', function() {
|
||||||
var string = '{{arr}}';
|
var string = '{{arr}}';
|
||||||
var data = { 'arr': [1, 2] };
|
var data = { arr: [1, 2] };
|
||||||
|
|
||||||
shouldCompileTo(string, data, data.arr.toString(), 'it works as expected');
|
shouldCompileTo(string, data, data.arr.toString(), 'it works as expected');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Mustache man page', function() {
|
it('Mustache man page', function() {
|
||||||
var string = 'Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}';
|
var string =
|
||||||
|
'Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}';
|
||||||
var data = {
|
var data = {
|
||||||
'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
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldCompileTo(string, data, 'Hello Chris. You have just won $10000! Well, $6000, after taxes.', 'the hello world mustache example works');
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
data,
|
||||||
|
'Hello Chris. You have just won $10000! Well, $6000, after taxes.',
|
||||||
|
'the hello world mustache example works'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GH-731: zero context rendering', function() {
|
it('GH-731: zero context rendering', function() {
|
||||||
shouldCompileTo('{{#foo}} This is {{bar}} ~ {{/foo}}', {foo: 0, bar: 'OK'}, ' This is ~ ');
|
shouldCompileTo(
|
||||||
|
'{{#foo}} This is {{bar}} ~ {{/foo}}',
|
||||||
|
{ foo: 0, bar: 'OK' },
|
||||||
|
' This is ~ '
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GH-820: zero pathed rendering', function() {
|
it('GH-820: zero pathed rendering', function() {
|
||||||
@@ -150,7 +201,9 @@ describe('Regressions', function() {
|
|||||||
|
|
||||||
it('GH-837: undefined values for helpers', function() {
|
it('GH-837: undefined values for helpers', function() {
|
||||||
var helpers = {
|
var helpers = {
|
||||||
str: function(value) { return value + ''; }
|
str: function(value) {
|
||||||
|
return value + '';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldCompileTo('{{str bar.baz}}', [{}, helpers], 'undefined');
|
shouldCompileTo('{{str bar.baz}}', [{}, helpers], 'undefined');
|
||||||
@@ -159,15 +212,13 @@ describe('Regressions', function() {
|
|||||||
it('GH-926: Depths and de-dupe', function() {
|
it('GH-926: Depths and de-dupe', function() {
|
||||||
var context = {
|
var context = {
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
data: [
|
data: [1],
|
||||||
1
|
notData: [1]
|
||||||
],
|
|
||||||
notData: [
|
|
||||||
1
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var template = CompilerContext.compile('{{#if dater}}{{#each data}}{{../name}}{{/each}}{{else}}{{#each notData}}{{../name}}{{/each}}{{/if}}');
|
var template = CompilerContext.compile(
|
||||||
|
'{{#if dater}}{{#each data}}{{../name}}{{/each}}{{else}}{{#each notData}}{{../name}}{{/each}}{{/if}}'
|
||||||
|
);
|
||||||
|
|
||||||
var result = template(context);
|
var result = template(context);
|
||||||
equals(result, 'foo');
|
equals(result, 'foo');
|
||||||
@@ -176,11 +227,15 @@ describe('Regressions', function() {
|
|||||||
it('GH-1021: Each empty string key', function() {
|
it('GH-1021: Each empty string key', function() {
|
||||||
var data = {
|
var data = {
|
||||||
'': 'foo',
|
'': 'foo',
|
||||||
'name': 'Chris',
|
name: 'Chris',
|
||||||
'value': 10000
|
value: 10000
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldCompileTo('{{#each data}}Key: {{@key}}\n{{/each}}', {data: data}, 'Key: \nKey: name\nKey: value\n');
|
shouldCompileTo(
|
||||||
|
'{{#each data}}Key: {{@key}}\n{{/each}}',
|
||||||
|
{ data: data },
|
||||||
|
'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() {
|
||||||
@@ -194,14 +249,23 @@ describe('Regressions', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldCompileToWithPartials(root, [{}, helpers, partials], true, '<partial>');
|
shouldCompileToWithPartials(
|
||||||
|
root,
|
||||||
|
[{}, helpers, partials],
|
||||||
|
true,
|
||||||
|
'<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';
|
||||||
shouldCompileTo('{{#each array}}{{@index}}{{.}}{{/each}}', {array: array}, '1foo3bar');
|
shouldCompileTo(
|
||||||
|
'{{#each array}}{{@index}}{{.}}{{/each}}',
|
||||||
|
{ array: array },
|
||||||
|
'1foo3bar'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GH-1093: Undefined helper context', function() {
|
it('GH-1093: Undefined helper context', function() {
|
||||||
@@ -216,28 +280,45 @@ 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';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldCompileTo('{{#each obj}}{{{helper}}}{{.}}{{/each}}', [{obj: obj}, helpers], 'notfoundbat');
|
shouldCompileTo(
|
||||||
|
'{{#each obj}}{{{helper}}}{{.}}{{/each}}',
|
||||||
|
[{ obj: obj }, helpers],
|
||||||
|
'notfoundbat'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support multiple levels of inline partials', function() {
|
it('should support multiple levels of inline partials', function() {
|
||||||
var string = '{{#> layout}}{{#*inline "subcontent"}}subcontent{{/inline}}{{/layout}}';
|
var string =
|
||||||
|
'{{#> layout}}{{#*inline "subcontent"}}subcontent{{/inline}}{{/layout}}';
|
||||||
var partials = {
|
var partials = {
|
||||||
doctype: 'doctype{{> content}}',
|
doctype: 'doctype{{> content}}',
|
||||||
layout: '{{#> doctype}}{{#*inline "content"}}layout{{> subcontent}}{{/inline}}{{/doctype}}'
|
layout:
|
||||||
|
'{{#> doctype}}{{#*inline "content"}}layout{{> subcontent}}{{/inline}}{{/doctype}}'
|
||||||
};
|
};
|
||||||
shouldCompileToWithPartials(string, [{}, {}, partials], true, 'doctypelayoutsubcontent');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[{}, {}, partials],
|
||||||
|
true,
|
||||||
|
'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() {
|
||||||
var string = '{{#> layout}}{{/layout}}';
|
var string = '{{#> layout}}{{/layout}}';
|
||||||
var partials = {
|
var partials = {
|
||||||
doctype: 'doctype{{> content}}',
|
doctype: 'doctype{{> content}}',
|
||||||
layout: '{{#> doctype}}{{#*inline "content"}}layout{{#> subcontent}}subcontent{{/subcontent}}{{/inline}}{{/doctype}}'
|
layout:
|
||||||
|
'{{#> doctype}}{{#*inline "content"}}layout{{#> subcontent}}subcontent{{/subcontent}}{{/inline}}{{/doctype}}'
|
||||||
};
|
};
|
||||||
shouldCompileToWithPartials(string, [{}, {}, partials], true, 'doctypelayoutsubcontent');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[{}, {}, partials],
|
||||||
|
true,
|
||||||
|
'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() {
|
||||||
var string = '{{#> layout}}Outer{{/layout}}';
|
var string = '{{#> layout}}Outer{{/layout}}';
|
||||||
@@ -261,39 +342,51 @@ describe('Regressions', function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
shouldCompileTo(
|
shouldCompileTo(
|
||||||
'{{#each array}}\n'
|
'{{#each array}}\n' +
|
||||||
+ ' 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}}\n'
|
' 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}}\n' +
|
||||||
+ ' 2. MYIF: {{#myif true}}{{../name}}={{../../name}}={{../../../name}}{{/myif}}\n'
|
' 2. MYIF: {{#myif true}}{{../name}}={{../../name}}={{../../../name}}{{/myif}}\n' +
|
||||||
+ '{{/each}}', [obj, helpers],
|
'{{/each}}',
|
||||||
' 1. IF: John--\n'
|
[obj, helpers],
|
||||||
+ ' 2. MYIF: John==\n');
|
' 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() {
|
||||||
var string =
|
var string =
|
||||||
'{{#*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}}' +
|
||||||
+ '{{#>test }}{{#each listTwo as |item|}}{{ item }}{{/each}}{{/test}}';
|
'{{#>test }}{{#each listTwo as |item|}}{{ item }}{{/each}}{{/test}}';
|
||||||
|
|
||||||
shouldCompileTo(string, { listOne: ['a'], listTwo: ['b'] }, 'ab', '');
|
shouldCompileTo(string, { listOne: ['a'], listTwo: ['b'] }, 'ab', '');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GH-1319: "unless" breaks when "each" value equals "null"', function() {
|
it('GH-1319: "unless" breaks when "each" value equals "null"', function() {
|
||||||
var string = '{{#each list}}{{#unless ./prop}}parent={{../value}} {{/unless}}{{/each}}';
|
var string =
|
||||||
shouldCompileTo(string, { value: 'parent', list: [ null, 'a'] }, 'parent=parent parent=parent ', '');
|
'{{#each list}}{{#unless ./prop}}parent={{../value}} {{/unless}}{{/each}}';
|
||||||
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
{ value: 'parent', list: [null, 'a'] },
|
||||||
|
'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() {
|
||||||
var string = 'template {{>partial}} template';
|
var string = 'template {{>partial}} template';
|
||||||
var partials = {
|
var partials = {
|
||||||
partialWithBlock: '{{#if @partial-block}} block {{> @partial-block}} block {{/if}}',
|
partialWithBlock:
|
||||||
|
'{{#if @partial-block}} block {{> @partial-block}} block {{/if}}',
|
||||||
partial: '{{#> partialWithBlock}} partial {{/partialWithBlock}}'
|
partial: '{{#> partialWithBlock}} partial {{/partialWithBlock}}'
|
||||||
};
|
};
|
||||||
shouldCompileToWithPartials(string, [{}, {}, partials], true, 'template block partial block template');
|
shouldCompileToWithPartials(
|
||||||
|
string,
|
||||||
|
[{}, {}, partials],
|
||||||
|
true,
|
||||||
|
'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();
|
||||||
|
|
||||||
@@ -301,26 +394,48 @@ describe('Regressions', function() {
|
|||||||
newHandlebarsInstance.registerHelper('loud', function(value) {
|
newHandlebarsInstance.registerHelper('loud', function(value) {
|
||||||
return value.toUpperCase();
|
return value.toUpperCase();
|
||||||
});
|
});
|
||||||
var result = newHandlebarsInstance.templates['test.hbs']({name: 'yehuda'});
|
var result = newHandlebarsInstance.templates['test.hbs']({
|
||||||
|
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(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
registerTemplate(newHandlebarsInstance);
|
registerTemplate(newHandlebarsInstance);
|
||||||
newHandlebarsInstance.templates['test.hbs']({});
|
newHandlebarsInstance.templates['test.hbs']({});
|
||||||
}, Handlebars.Exception, 'Missing helper: "loud"');
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'Missing helper: "loud"'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// This is a only slightly modified precompiled templated from compiled with 4.2.1
|
// This is a only slightly modified precompiled templated from compiled with 4.2.1
|
||||||
function registerTemplate(Handlebars) {
|
function registerTemplate(Handlebars) {
|
||||||
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
var template = Handlebars.template,
|
||||||
templates['test.hbs'] = template({'compiler': [7, '>= 4.0.0'], 'main': function(container, depth0, helpers, partials, data) {
|
templates = (Handlebars.templates = Handlebars.templates || {});
|
||||||
return container.escapeExpression((helpers.loud || (depth0 && depth0.loud) || helpers.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}), (depth0 != null ? depth0.name : depth0), {'name': 'loud', 'hash': {}, 'data': data}))
|
templates['test.hbs'] = template({
|
||||||
+ '\n\n';
|
compiler: [7, '>= 4.0.0'],
|
||||||
}, 'useData': true});
|
main: function(container, depth0, helpers, partials, data) {
|
||||||
|
return (
|
||||||
|
container.escapeExpression(
|
||||||
|
(
|
||||||
|
helpers.loud ||
|
||||||
|
(depth0 && depth0.loud) ||
|
||||||
|
helpers.helperMissing
|
||||||
|
).call(
|
||||||
|
depth0 != null ? depth0 : container.nullContext || {},
|
||||||
|
depth0 != null ? depth0.name : depth0,
|
||||||
|
{ name: 'loud', hash: {}, data: data }
|
||||||
|
)
|
||||||
|
) + '\n\n'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
useData: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -352,7 +467,7 @@ describe('Regressions', function() {
|
|||||||
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
|
||||||
|
|||||||
+48
-16
@@ -1,34 +1,58 @@
|
|||||||
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(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Handlebars.template({});
|
Handlebars.template({});
|
||||||
}, Error, 'Unknown template object: object');
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
'Unknown template object: object'
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Handlebars.template();
|
Handlebars.template();
|
||||||
}, Error, 'Unknown template object: undefined');
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
'Unknown template object: undefined'
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Handlebars.template('');
|
Handlebars.template('');
|
||||||
}, Error, 'Unknown template object: string');
|
},
|
||||||
|
Error,
|
||||||
|
'Unknown template object: string'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should throw on version mismatch', function() {
|
it('should throw on version mismatch', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Handlebars.template({
|
Handlebars.template({
|
||||||
main: {},
|
main: {},
|
||||||
compiler: [Handlebars.COMPILER_REVISION + 1]
|
compiler: [Handlebars.COMPILER_REVISION + 1]
|
||||||
});
|
});
|
||||||
}, Error, /Template was precompiled with a newer version of Handlebars than the current runtime/);
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
/Template was precompiled with a newer version of Handlebars than the current runtime/
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Handlebars.template({
|
Handlebars.template({
|
||||||
main: {},
|
main: {},
|
||||||
compiler: [Handlebars.LAST_COMPATIBLE_COMPILER_REVISION - 1]
|
compiler: [Handlebars.LAST_COMPATIBLE_COMPILER_REVISION - 1]
|
||||||
});
|
});
|
||||||
}, Error, /Template was precompiled with an older version of Handlebars than the current runtime/);
|
},
|
||||||
shouldThrow(function() {
|
Error,
|
||||||
|
/Template was precompiled with an older version of Handlebars than the current runtime/
|
||||||
|
);
|
||||||
|
shouldThrow(
|
||||||
|
function() {
|
||||||
Handlebars.template({
|
Handlebars.template({
|
||||||
main: {}
|
main: {}
|
||||||
});
|
});
|
||||||
}, Error, /Template was precompiled with an older version of Handlebars than the current runtime/);
|
},
|
||||||
|
Error,
|
||||||
|
/Template was precompiled with an older version of Handlebars than the current runtime/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -38,23 +62,31 @@ describe('runtime', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should throw for depthed methods without depths', function() {
|
it('should throw for depthed methods without depths', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
var template = Handlebars.compile('{{#foo}}{{../bar}}{{/foo}}');
|
var template = Handlebars.compile('{{#foo}}{{../bar}}{{/foo}}');
|
||||||
// Calling twice to hit the non-compiled case.
|
// Calling twice to hit the non-compiled case.
|
||||||
template._setup({});
|
template._setup({});
|
||||||
template._setup({});
|
template._setup({});
|
||||||
template._child(1);
|
template._child(1);
|
||||||
}, Error, 'must pass parent depths');
|
},
|
||||||
|
Error,
|
||||||
|
'must pass parent depths'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw for block param methods without params', function() {
|
it('should throw for block param methods without params', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
var template = Handlebars.compile('{{#foo as |foo|}}{{foo}}{{/foo}}');
|
var template = Handlebars.compile('{{#foo as |foo|}}{{foo}}{{/foo}}');
|
||||||
// Calling twice to hit the non-compiled case.
|
// Calling twice to hit the non-compiled case.
|
||||||
template._setup({});
|
template._setup({});
|
||||||
template._setup({});
|
template._setup({});
|
||||||
template._child(1);
|
template._child(1);
|
||||||
}, Error, 'must pass block params');
|
},
|
||||||
|
Error,
|
||||||
|
'must pass block params'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should expose child template', function() {
|
it('should expose child template', function() {
|
||||||
var template = Handlebars.compile('{{#foo}}bar{{/foo}}');
|
var template = Handlebars.compile('{{#foo}}bar{{/foo}}');
|
||||||
|
|||||||
+103
-39
@@ -19,39 +19,58 @@ describe('security issues', function() {
|
|||||||
.toCompileTo('');
|
.toCompileTo('');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should allow the "constructor" property to be accessed if it is enumerable', function() {
|
it('should allow the "constructor" property to be accessed if it is enumerable', function() {
|
||||||
shouldCompileTo('{{constructor.name}}', {'constructor': {
|
shouldCompileTo(
|
||||||
'name': 'here we go'
|
'{{constructor.name}}',
|
||||||
}}, 'here we go');
|
{
|
||||||
shouldCompileTo('{{lookup (lookup this "constructor") "name"}}', {'constructor': {
|
constructor: {
|
||||||
'name': 'here we go'
|
name: 'here we go'
|
||||||
}}, 'here we go');
|
}
|
||||||
|
},
|
||||||
|
'here we go'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{lookup (lookup this "constructor") "name"}}',
|
||||||
|
{
|
||||||
|
constructor: {
|
||||||
|
name: 'here we go'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'here we go'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow the "constructor" property to be accessed if it is enumerable', function() {
|
it('should allow the "constructor" property to be accessed if it is enumerable', function() {
|
||||||
shouldCompileTo('{{lookup (lookup this "constructor") "name"}}', {'constructor': {
|
shouldCompileTo(
|
||||||
'name': 'here we go'
|
'{{lookup (lookup this "constructor") "name"}}',
|
||||||
}}, 'here we go');
|
{
|
||||||
|
constructor: {
|
||||||
|
name: 'here we go'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'here we go'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should allow prototype properties that are not constructors', function() {
|
it('should allow prototype properties that are not constructors', function() {
|
||||||
function TestClass() {
|
function TestClass() {}
|
||||||
}
|
|
||||||
|
|
||||||
Object.defineProperty(TestClass.prototype, 'abc', {
|
Object.defineProperty(TestClass.prototype, 'abc', {
|
||||||
get: function() {
|
get: function() {
|
||||||
return 'xyz';
|
return 'xyz';
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
shouldCompileTo('{{#with this as |obj|}}{{obj.abc}}{{/with}}',
|
shouldCompileTo(
|
||||||
new TestClass(), 'xyz');
|
'{{#with this as |obj|}}{{obj.abc}}{{/with}}',
|
||||||
shouldCompileTo('{{#with this as |obj|}}{{lookup obj "abc"}}{{/with}}',
|
new TestClass(),
|
||||||
new TestClass(), 'xyz');
|
'xyz'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'{{#with this as |obj|}}{{lookup obj "abc"}}{{/with}}',
|
||||||
|
new TestClass(),
|
||||||
|
'xyz'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -69,7 +88,9 @@ describe('security issues', function() {
|
|||||||
});
|
});
|
||||||
it('should throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function() {
|
it('should throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(function() {
|
||||||
var template = Handlebars.compile('{{#helperMissing}}{{/helperMissing}}');
|
var template = Handlebars.compile(
|
||||||
|
'{{#helperMissing}}{{/helperMissing}}'
|
||||||
|
);
|
||||||
template({});
|
template({});
|
||||||
}, Error);
|
}, Error);
|
||||||
});
|
});
|
||||||
@@ -77,14 +98,24 @@ describe('security issues', function() {
|
|||||||
var functionCalls = [];
|
var functionCalls = [];
|
||||||
expect(function() {
|
expect(function() {
|
||||||
var template = Handlebars.compile('{{blockHelperMissing "abc" .}}');
|
var template = Handlebars.compile('{{blockHelperMissing "abc" .}}');
|
||||||
template({ fn: function() { functionCalls.push('called'); }});
|
template({
|
||||||
|
fn: function() {
|
||||||
|
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() {
|
||||||
shouldThrow(function() {
|
shouldThrow(function() {
|
||||||
var template = Handlebars.compile('{{#blockHelperMissing .}}{{/blockHelperMissing}}');
|
var template = Handlebars.compile(
|
||||||
template({ fn: function() { return 'functionInData';}});
|
'{{#blockHelperMissing .}}{{/blockHelperMissing}}'
|
||||||
|
);
|
||||||
|
template({
|
||||||
|
fn: function() {
|
||||||
|
return 'functionInData';
|
||||||
|
}
|
||||||
|
});
|
||||||
}, Error);
|
}, Error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -95,17 +126,28 @@ describe('security issues', function() {
|
|||||||
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('{{#helperMissing}}{{/helperMissing}}');
|
var template = Handlebars.compile(
|
||||||
|
'{{#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({ fn: function() { functionCalls.push('called'); }}, {allowCallsToHelperMissing: true});
|
template(
|
||||||
|
{
|
||||||
|
fn: function() {
|
||||||
|
functionCalls.push('called');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ 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('{{#blockHelperMissing true}}sdads{{/blockHelperMissing}}');
|
var template = Handlebars.compile(
|
||||||
|
'{{#blockHelperMissing true}}sdads{{/blockHelperMissing}}'
|
||||||
|
);
|
||||||
template({}, { allowCallsToHelperMissing: true });
|
template({}, { allowCallsToHelperMissing: true });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -113,14 +155,16 @@ 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
|
||||||
}
|
}
|
||||||
expectTemplate('{{__defineGetter__ "undefined" valueOf }}' +
|
expectTemplate(
|
||||||
|
'{{__defineGetter__ "undefined" valueOf }}' +
|
||||||
'{{#with __lookupGetter__ }}' +
|
'{{#with __lookupGetter__ }}' +
|
||||||
'{{__defineGetter__ "propertyIsEnumerable" (this.bind (this.bind 1)) }}' +
|
'{{__defineGetter__ "propertyIsEnumerable" (this.bind (this.bind 1)) }}' +
|
||||||
'{{constructor.name}}' +
|
'{{constructor.name}}' +
|
||||||
'{{/with}}')
|
'{{/with}}'
|
||||||
|
)
|
||||||
.withInput({})
|
.withInput({})
|
||||||
.toThrow(/Missing helper: "__defineGetter__"/);
|
.toThrow(/Missing helper: "__defineGetter__"/);
|
||||||
});
|
});
|
||||||
@@ -128,17 +172,37 @@ describe('security issues', function() {
|
|||||||
|
|
||||||
describe('GH-1595', function() {
|
describe('GH-1595', function() {
|
||||||
it('properties, that are required to be enumerable', function() {
|
it('properties, that are required to be enumerable', function() {
|
||||||
expectTemplate('{{constructor}}').withInput({}).toCompileTo('');
|
expectTemplate('{{constructor}}')
|
||||||
expectTemplate('{{__defineGetter__}}').withInput({}).toCompileTo('');
|
.withInput({})
|
||||||
expectTemplate('{{__defineSetter__}}').withInput({}).toCompileTo('');
|
.toCompileTo('');
|
||||||
expectTemplate('{{__lookupGetter__}}').withInput({}).toCompileTo('');
|
expectTemplate('{{__defineGetter__}}')
|
||||||
expectTemplate('{{__proto__}}').withInput({}).toCompileTo('');
|
.withInput({})
|
||||||
|
.toCompileTo('');
|
||||||
|
expectTemplate('{{__defineSetter__}}')
|
||||||
|
.withInput({})
|
||||||
|
.toCompileTo('');
|
||||||
|
expectTemplate('{{__lookupGetter__}}')
|
||||||
|
.withInput({})
|
||||||
|
.toCompileTo('');
|
||||||
|
expectTemplate('{{__proto__}}')
|
||||||
|
.withInput({})
|
||||||
|
.toCompileTo('');
|
||||||
|
|
||||||
expectTemplate('{{lookup "constructor"}}').withInput({}).toCompileTo('');
|
expectTemplate('{{lookup "constructor"}}')
|
||||||
expectTemplate('{{lookup "__defineGetter__"}}').withInput({}).toCompileTo('');
|
.withInput({})
|
||||||
expectTemplate('{{lookup "__defineSetter__"}}').withInput({}).toCompileTo('');
|
.toCompileTo('');
|
||||||
expectTemplate('{{lookup "__lookupGetter__"}}').withInput({}).toCompileTo('');
|
expectTemplate('{{lookup "__defineGetter__"}}')
|
||||||
expectTemplate('{{lookup "__proto__"}}').withInput({}).toCompileTo('');
|
.withInput({})
|
||||||
|
.toCompileTo('');
|
||||||
|
expectTemplate('{{lookup "__defineSetter__"}}')
|
||||||
|
.withInput({})
|
||||||
|
.toCompileTo('');
|
||||||
|
expectTemplate('{{lookup "__lookupGetter__"}}')
|
||||||
|
.withInput({})
|
||||||
|
.toCompileTo('');
|
||||||
|
expectTemplate('{{lookup "__proto__"}}')
|
||||||
|
.withInput({})
|
||||||
|
.toCompileTo('');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+10
-4
@@ -13,20 +13,26 @@ describe('source-map', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should safely include source map info', function() {
|
it('should safely include source map info', function() {
|
||||||
var template = Handlebars.precompile('{{hello}}', {destName: 'dest.js', srcName: 'src.hbs'});
|
var template = Handlebars.precompile('{{hello}}', {
|
||||||
|
destName: 'dest.js',
|
||||||
|
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 = ' b{{hello}} \n {{bar}}a {{#block arg hash=(subex 1 subval)}}{{/block}}',
|
var templateSource =
|
||||||
template = Handlebars.precompile(templateSource, {destName: 'dest.js', srcName: 'src.hbs'});
|
' b{{hello}} \n {{bar}}a {{#block arg hash=(subex 1 subval)}}{{/block}}',
|
||||||
|
template = Handlebars.precompile(templateSource, {
|
||||||
|
destName: 'dest.js',
|
||||||
|
srcName: 'src.hbs'
|
||||||
|
});
|
||||||
|
|
||||||
if (template.map) {
|
if (template.map) {
|
||||||
var consumer = new SourceMapConsumer(template.map),
|
var consumer = new SourceMapConsumer(template.map),
|
||||||
lines = template.code.split('\n'),
|
lines = template.code.split('\n'),
|
||||||
srcLines = templateSource.split('\n'),
|
srcLines = templateSource.split('\n'),
|
||||||
|
|
||||||
generated = grepLine('" b"', lines),
|
generated = grepLine('" b"', lines),
|
||||||
source = grepLine(' b', srcLines);
|
source = grepLine(' b', srcLines);
|
||||||
|
|
||||||
|
|||||||
+23
-11
@@ -9,7 +9,7 @@ describe('spec', function() {
|
|||||||
|
|
||||||
var specDir = __dirname + '/mustache/specs/';
|
var specDir = __dirname + '/mustache/specs/';
|
||||||
var specs = _.filter(fs.readdirSync(specDir), function(name) {
|
var specs = _.filter(fs.readdirSync(specDir), function(name) {
|
||||||
return (/.*\.json$/).test(name);
|
return /.*\.json$/.test(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
_.each(specs, function(name) {
|
_.each(specs, function(name) {
|
||||||
@@ -17,16 +17,17 @@ describe('spec', function() {
|
|||||||
_.each(spec.tests, function(test) {
|
_.each(spec.tests, function(test) {
|
||||||
// Our lambda implementation knowingly deviates from the optional Mustace lambda spec
|
// Our lambda implementation knowingly deviates from the optional Mustace lambda spec
|
||||||
// We also do not support alternative delimeters
|
// We also do not support alternative delimeters
|
||||||
if (name === '~lambdas.json'
|
if (
|
||||||
|
name === '~lambdas.json' ||
|
||||||
// We also choose to throw if paritals are not found
|
// We also choose to throw if paritals are not found
|
||||||
|| (name === 'partials.json' && test.name === 'Failed Lookup')
|
(name === 'partials.json' && test.name === 'Failed Lookup') ||
|
||||||
|
|
||||||
// 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)
|
_.any(test.partials, function(partial) {
|
||||||
|| _.any(test.partials, function(partial) { return (/\{\{=/).test(partial); })) {
|
return /\{\{=/.test(partial);
|
||||||
|
})
|
||||||
|
) {
|
||||||
it.skip(name + ' - ' + test.name);
|
it.skip(name + ' - ' + test.name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -40,9 +41,20 @@ describe('spec', function() {
|
|||||||
}
|
}
|
||||||
it(name + ' - ' + test.name, function() {
|
it(name + ' - ' + test.name, function() {
|
||||||
if (test.partials) {
|
if (test.partials) {
|
||||||
shouldCompileToWithPartials(test.template, [data, {}, test.partials, true], true, test.expected, test.desc + ' "' + test.template + '"');
|
shouldCompileToWithPartials(
|
||||||
|
test.template,
|
||||||
|
[data, {}, test.partials, true],
|
||||||
|
true,
|
||||||
|
test.expected,
|
||||||
|
test.desc + ' "' + test.template + '"'
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
shouldCompileTo(test.template, [data, {}, {}, true], test.expected, test.desc + ' "' + test.template + '"');
|
shouldCompileTo(
|
||||||
|
test.template,
|
||||||
|
[data, {}, {}, true],
|
||||||
|
test.expected,
|
||||||
|
test.desc + ' "' + test.template + '"'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+105
-34
@@ -3,19 +3,27 @@ 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() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
var template = CompilerContext.compile('{{hello}}', { strict: true });
|
var template = CompilerContext.compile('{{hello}}', { strict: true });
|
||||||
|
|
||||||
template({});
|
template({});
|
||||||
}, Exception, /"hello" not defined in/);
|
},
|
||||||
|
Exception,
|
||||||
|
/"hello" not defined in/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should error on missing child', function() {
|
it('should error on missing child', function() {
|
||||||
var template = CompilerContext.compile('{{hello.bar}}', { strict: true });
|
var template = CompilerContext.compile('{{hello.bar}}', { strict: true });
|
||||||
equals(template({ hello: { bar: 'foo' } }), 'foo');
|
equals(template({ hello: { bar: 'foo' } }), 'foo');
|
||||||
|
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
template({ hello: {} });
|
template({ hello: {} });
|
||||||
}, Exception, /"bar" not defined in/);
|
},
|
||||||
|
Exception,
|
||||||
|
/"bar" not defined in/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should handle explicit undefined', function() {
|
it('should handle explicit undefined', function() {
|
||||||
var template = CompilerContext.compile('{{hello.bar}}', { strict: true });
|
var template = CompilerContext.compile('{{hello.bar}}', { strict: true });
|
||||||
@@ -23,11 +31,18 @@ describe('strict', function() {
|
|||||||
equals(template({ hello: { bar: undefined } }), '');
|
equals(template({ hello: { bar: undefined } }), '');
|
||||||
});
|
});
|
||||||
it('should error on missing property lookup in known helpers mode', function() {
|
it('should error on missing property lookup in known helpers mode', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
var template = CompilerContext.compile('{{hello}}', {strict: true, knownHelpersOnly: true});
|
function() {
|
||||||
|
var template = CompilerContext.compile('{{hello}}', {
|
||||||
|
strict: true,
|
||||||
|
knownHelpersOnly: true
|
||||||
|
});
|
||||||
|
|
||||||
template({});
|
template({});
|
||||||
}, Exception, /"hello" not defined in/);
|
},
|
||||||
|
Exception,
|
||||||
|
/"hello" not defined in/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should error on missing context', function() {
|
it('should error on missing context', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(function() {
|
||||||
@@ -47,45 +62,81 @@ describe('strict', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not run helperMissing for helper calls', function() {
|
it('should not run helperMissing for helper calls', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
var template = CompilerContext.compile('{{hello foo}}', {strict: true});
|
function() {
|
||||||
|
var template = CompilerContext.compile('{{hello foo}}', {
|
||||||
|
strict: true
|
||||||
|
});
|
||||||
|
|
||||||
template({ foo: true });
|
template({ foo: true });
|
||||||
}, Exception, /"hello" not defined in/);
|
},
|
||||||
|
Exception,
|
||||||
|
/"hello" not defined in/
|
||||||
|
);
|
||||||
|
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
var template = CompilerContext.compile('{{#hello foo}}{{/hello}}', {strict: true});
|
function() {
|
||||||
|
var template = CompilerContext.compile('{{#hello foo}}{{/hello}}', {
|
||||||
|
strict: true
|
||||||
|
});
|
||||||
|
|
||||||
template({ foo: true });
|
template({ foo: true });
|
||||||
}, Exception, /"hello" not defined in/);
|
},
|
||||||
|
Exception,
|
||||||
|
/"hello" not defined in/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should throw on ambiguous blocks', function() {
|
it('should throw on ambiguous blocks', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
var template = CompilerContext.compile('{{#hello}}{{/hello}}', {strict: true});
|
function() {
|
||||||
|
var template = CompilerContext.compile('{{#hello}}{{/hello}}', {
|
||||||
|
strict: true
|
||||||
|
});
|
||||||
|
|
||||||
template({});
|
template({});
|
||||||
}, Exception, /"hello" not defined in/);
|
},
|
||||||
|
Exception,
|
||||||
|
/"hello" not defined in/
|
||||||
|
);
|
||||||
|
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
var template = CompilerContext.compile('{{^hello}}{{/hello}}', {strict: true});
|
function() {
|
||||||
|
var template = CompilerContext.compile('{{^hello}}{{/hello}}', {
|
||||||
|
strict: true
|
||||||
|
});
|
||||||
|
|
||||||
template({});
|
template({});
|
||||||
}, Exception, /"hello" not defined in/);
|
},
|
||||||
|
Exception,
|
||||||
|
/"hello" not defined in/
|
||||||
|
);
|
||||||
|
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
var template = CompilerContext.compile('{{#hello.bar}}{{/hello.bar}}', {strict: true});
|
function() {
|
||||||
|
var template = CompilerContext.compile(
|
||||||
|
'{{#hello.bar}}{{/hello.bar}}',
|
||||||
|
{ strict: true }
|
||||||
|
);
|
||||||
|
|
||||||
template({ hello: {} });
|
template({ hello: {} });
|
||||||
}, Exception, /"bar" not defined in/);
|
},
|
||||||
|
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() {
|
||||||
var template = CompilerContext.compile('{{#unless foo}}success{{/unless}}', {strict: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#unless foo}}success{{/unless}}',
|
||||||
|
{ strict: true }
|
||||||
|
);
|
||||||
equals(template({}), 'success');
|
equals(template({}), 'success');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow undefined hash when passed to helpers', function() {
|
it('should allow undefined hash when passed to helpers', function() {
|
||||||
var template = CompilerContext.compile('{{helper value=@foo}}', {strict: true});
|
var template = CompilerContext.compile('{{helper value=@foo}}', {
|
||||||
|
strict: true
|
||||||
|
});
|
||||||
var helpers = {
|
var helpers = {
|
||||||
helper: function(options) {
|
helper: function(options) {
|
||||||
equals('value' in options.hash, true);
|
equals('value' in options.hash, true);
|
||||||
@@ -97,15 +148,23 @@ describe('strict', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show error location on missing property lookup', function() {
|
it('should show error location on missing property lookup', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
var template = CompilerContext.compile('\n\n\n {{hello}}', {strict: true});
|
function() {
|
||||||
|
var template = CompilerContext.compile('\n\n\n {{hello}}', {
|
||||||
|
strict: true
|
||||||
|
});
|
||||||
template({});
|
template({});
|
||||||
}, Exception, '"hello" not defined in [object Object] - 4:5');
|
},
|
||||||
|
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}}', {strict: true});
|
var template = CompilerContext.compile('\n\n\n {{hello}}', {
|
||||||
|
strict: true
|
||||||
|
});
|
||||||
template({});
|
template({});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
equals(error.lineNumber, 4);
|
equals(error.lineNumber, 4);
|
||||||
@@ -118,25 +177,33 @@ describe('strict', function() {
|
|||||||
|
|
||||||
describe('assume objects', function() {
|
describe('assume objects', function() {
|
||||||
it('should ignore missing property', function() {
|
it('should ignore missing property', function() {
|
||||||
var template = CompilerContext.compile('{{hello}}', {assumeObjects: true});
|
var template = CompilerContext.compile('{{hello}}', {
|
||||||
|
assumeObjects: true
|
||||||
|
});
|
||||||
|
|
||||||
equal(template({}), '');
|
equal(template({}), '');
|
||||||
});
|
});
|
||||||
it('should ignore missing child', function() {
|
it('should ignore missing child', function() {
|
||||||
var template = CompilerContext.compile('{{hello.bar}}', {assumeObjects: true});
|
var template = CompilerContext.compile('{{hello.bar}}', {
|
||||||
|
assumeObjects: true
|
||||||
|
});
|
||||||
|
|
||||||
equal(template({ hello: {} }), '');
|
equal(template({ hello: {} }), '');
|
||||||
});
|
});
|
||||||
it('should error on missing object', function() {
|
it('should error on missing object', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(function() {
|
||||||
var template = CompilerContext.compile('{{hello.bar}}', {assumeObjects: true});
|
var template = CompilerContext.compile('{{hello.bar}}', {
|
||||||
|
assumeObjects: true
|
||||||
|
});
|
||||||
|
|
||||||
template({});
|
template({});
|
||||||
}, Error);
|
}, Error);
|
||||||
});
|
});
|
||||||
it('should error on missing context', function() {
|
it('should error on missing context', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(function() {
|
||||||
var template = CompilerContext.compile('{{hello}}', {assumeObjects: true});
|
var template = CompilerContext.compile('{{hello}}', {
|
||||||
|
assumeObjects: true
|
||||||
|
});
|
||||||
|
|
||||||
template();
|
template();
|
||||||
}, Error);
|
}, Error);
|
||||||
@@ -144,14 +211,18 @@ describe('strict', function() {
|
|||||||
|
|
||||||
it('should error on missing data lookup', function() {
|
it('should error on missing data lookup', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(function() {
|
||||||
var template = CompilerContext.compile('{{@hello.bar}}', {assumeObjects: true});
|
var template = CompilerContext.compile('{{@hello.bar}}', {
|
||||||
|
assumeObjects: true
|
||||||
|
});
|
||||||
|
|
||||||
template();
|
template();
|
||||||
}, Error);
|
}, Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should execute blockHelperMissing', function() {
|
it('should execute blockHelperMissing', function() {
|
||||||
var template = CompilerContext.compile('{{^hello}}foo{{/hello}}', {assumeObjects: true});
|
var template = CompilerContext.compile('{{^hello}}foo{{/hello}}', {
|
||||||
|
assumeObjects: true
|
||||||
|
});
|
||||||
|
|
||||||
equals(template({}), 'foo');
|
equals(template({}), 'foo');
|
||||||
});
|
});
|
||||||
|
|||||||
+100
-30
@@ -1,6 +1,8 @@
|
|||||||
describe('string params mode', function() {
|
describe('string params mode', function() {
|
||||||
it('arguments to helpers can be retrieved from options hash in string form', function() {
|
it('arguments to helpers can be retrieved from options hash in string form', function() {
|
||||||
var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {stringParams: true});
|
var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {
|
||||||
|
stringParams: true
|
||||||
|
});
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
wycats: function(passiveVoice, noun) {
|
wycats: function(passiveVoice, noun) {
|
||||||
@@ -10,55 +12,97 @@ describe('string params mode', function() {
|
|||||||
|
|
||||||
var result = template({}, { helpers: helpers });
|
var result = template({}, { helpers: helpers });
|
||||||
|
|
||||||
equals(result, 'HELP ME MY BOSS is.a slave.driver', 'String parameters output');
|
equals(
|
||||||
|
result,
|
||||||
|
'HELP ME MY BOSS is.a slave.driver',
|
||||||
|
'String parameters output'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('when using block form, arguments to helpers can be retrieved from options hash in string form', function() {
|
it('when using block form, arguments to helpers can be retrieved from options hash in string form', function() {
|
||||||
var template = CompilerContext.compile('{{#wycats is.a slave.driver}}help :({{/wycats}}', {stringParams: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#wycats is.a slave.driver}}help :({{/wycats}}',
|
||||||
|
{ stringParams: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
wycats: function(passiveVoice, noun, options) {
|
wycats: function(passiveVoice, noun, options) {
|
||||||
return 'HELP ME MY BOSS ' + passiveVoice + ' ' +
|
return (
|
||||||
noun + ': ' + options.fn(this);
|
'HELP ME MY BOSS ' +
|
||||||
|
passiveVoice +
|
||||||
|
' ' +
|
||||||
|
noun +
|
||||||
|
': ' +
|
||||||
|
options.fn(this)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({}, { helpers: helpers });
|
var result = template({}, { helpers: helpers });
|
||||||
|
|
||||||
equals(result, 'HELP ME MY BOSS is.a slave.driver: help :(', 'String parameters output');
|
equals(
|
||||||
|
result,
|
||||||
|
'HELP ME MY BOSS is.a slave.driver: help :(',
|
||||||
|
'String parameters output'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('when inside a block in String mode, .. passes the appropriate context in the options hash', function() {
|
it('when inside a block in String mode, .. passes the appropriate context in the options hash', function() {
|
||||||
var template = CompilerContext.compile('{{#with dale}}{{tomdale ../need dad.joke}}{{/with}}', {stringParams: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#with dale}}{{tomdale ../need dad.joke}}{{/with}}',
|
||||||
|
{ stringParams: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
tomdale: function(desire, noun, options) {
|
tomdale: function(desire, noun, options) {
|
||||||
return 'STOP ME FROM READING HACKER NEWS I ' +
|
return (
|
||||||
options.contexts[0][desire] + ' ' + noun;
|
'STOP ME FROM READING HACKER NEWS I ' +
|
||||||
|
options.contexts[0][desire] +
|
||||||
|
' ' +
|
||||||
|
noun
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
'with': function(context, options) {
|
with: function(context, options) {
|
||||||
return options.fn(options.contexts[0][context]);
|
return options.fn(options.contexts[0][context]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({
|
var result = template(
|
||||||
|
{
|
||||||
dale: {},
|
dale: {},
|
||||||
|
|
||||||
need: 'need-a'
|
need: 'need-a'
|
||||||
}, {helpers: helpers});
|
},
|
||||||
|
{ helpers: helpers }
|
||||||
|
);
|
||||||
|
|
||||||
equals(result, 'STOP ME FROM READING HACKER NEWS I need-a dad.joke', 'Proper context variable output');
|
equals(
|
||||||
|
result,
|
||||||
|
'STOP ME FROM READING HACKER NEWS I need-a dad.joke',
|
||||||
|
'Proper context variable output'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('information about the types is passed along', function() {
|
it('information about the types is passed along', function() {
|
||||||
var template = CompilerContext.compile("{{tomdale 'need' dad.joke true false}}", { stringParams: true });
|
var template = CompilerContext.compile(
|
||||||
|
"{{tomdale 'need' dad.joke true false}}",
|
||||||
|
{ stringParams: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
tomdale: function(desire, noun, trueBool, falseBool, options) {
|
tomdale: function(desire, noun, trueBool, falseBool, options) {
|
||||||
equal(options.types[0], 'StringLiteral', 'the string type is passed');
|
equal(options.types[0], 'StringLiteral', 'the string type is passed');
|
||||||
equal(options.types[1], 'PathExpression', 'the expression type is passed');
|
equal(
|
||||||
equal(options.types[2], 'BooleanLiteral', 'the expression type is passed');
|
options.types[1],
|
||||||
|
'PathExpression',
|
||||||
|
'the expression type is passed'
|
||||||
|
);
|
||||||
|
equal(
|
||||||
|
options.types[2],
|
||||||
|
'BooleanLiteral',
|
||||||
|
'the expression type is passed'
|
||||||
|
);
|
||||||
equal(desire, 'need', 'the string form is passed for strings');
|
equal(desire, 'need', 'the string form is passed for strings');
|
||||||
equal(noun, 'dad.joke', 'the string form is passed for expressions');
|
equal(noun, 'dad.joke', 'the string form is passed for expressions');
|
||||||
equal(trueBool, true, 'raw booleans are passed through');
|
equal(trueBool, true, 'raw booleans are passed through');
|
||||||
@@ -72,7 +116,10 @@ describe('string params mode', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('hash parameters get type information', function() {
|
it('hash parameters get type information', function() {
|
||||||
var template = CompilerContext.compile("{{tomdale he.says desire='need' noun=dad.joke bool=true}}", { stringParams: true });
|
var template = CompilerContext.compile(
|
||||||
|
"{{tomdale he.says desire='need' noun=dad.joke bool=true}}",
|
||||||
|
{ stringParams: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
tomdale: function(exclamation, options) {
|
tomdale: function(exclamation, options) {
|
||||||
@@ -94,7 +141,10 @@ describe('string params mode', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('hash parameters get context information', function() {
|
it('hash parameters get context information', function() {
|
||||||
var template = CompilerContext.compile("{{#with dale}}{{tomdale he.says desire='need' noun=../dad/joke bool=true}}{{/with}}", { stringParams: true });
|
var template = CompilerContext.compile(
|
||||||
|
"{{#with dale}}{{tomdale he.says desire='need' noun=../dad/joke bool=true}}{{/with}}",
|
||||||
|
{ stringParams: true }
|
||||||
|
);
|
||||||
|
|
||||||
var context = { dale: {} };
|
var context = { dale: {} };
|
||||||
|
|
||||||
@@ -110,7 +160,7 @@ describe('string params mode', function() {
|
|||||||
equal(options.hash.bool, true);
|
equal(options.hash.bool, true);
|
||||||
return 'Helper called';
|
return 'Helper called';
|
||||||
},
|
},
|
||||||
'with': function(withContext, options) {
|
with: function(withContext, options) {
|
||||||
return options.fn(options.contexts[0][withContext]);
|
return options.fn(options.contexts[0][withContext]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -120,34 +170,52 @@ describe('string params mode', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('when inside a block in String mode, .. passes the appropriate context in the options hash to a block helper', function() {
|
it('when inside a block in String mode, .. passes the appropriate context in the options hash to a block helper', function() {
|
||||||
var template = CompilerContext.compile('{{#with dale}}{{#tomdale ../need dad.joke}}wot{{/tomdale}}{{/with}}', {stringParams: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#with dale}}{{#tomdale ../need dad.joke}}wot{{/tomdale}}{{/with}}',
|
||||||
|
{ stringParams: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
tomdale: function(desire, noun, options) {
|
tomdale: function(desire, noun, options) {
|
||||||
return 'STOP ME FROM READING HACKER NEWS I ' +
|
return (
|
||||||
options.contexts[0][desire] + ' ' + noun + ' ' +
|
'STOP ME FROM READING HACKER NEWS I ' +
|
||||||
options.fn(this);
|
options.contexts[0][desire] +
|
||||||
|
' ' +
|
||||||
|
noun +
|
||||||
|
' ' +
|
||||||
|
options.fn(this)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
'with': function(context, options) {
|
with: function(context, options) {
|
||||||
return options.fn(options.contexts[0][context]);
|
return options.fn(options.contexts[0][context]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({
|
var result = template(
|
||||||
|
{
|
||||||
dale: {},
|
dale: {},
|
||||||
|
|
||||||
need: 'need-a'
|
need: 'need-a'
|
||||||
}, {helpers: helpers});
|
},
|
||||||
|
{ helpers: helpers }
|
||||||
|
);
|
||||||
|
|
||||||
equals(result, 'STOP ME FROM READING HACKER NEWS I need-a dad.joke wot', 'Proper context variable output');
|
equals(
|
||||||
|
result,
|
||||||
|
'STOP ME FROM READING HACKER NEWS I need-a dad.joke wot',
|
||||||
|
'Proper context variable output'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('with nested block ambiguous', function() {
|
it('with nested block ambiguous', function() {
|
||||||
var template = CompilerContext.compile('{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}', {stringParams: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}',
|
||||||
|
{ stringParams: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
'with': function() {
|
with: function() {
|
||||||
return 'WITH';
|
return 'WITH';
|
||||||
},
|
},
|
||||||
view: function() {
|
view: function() {
|
||||||
@@ -160,7 +228,9 @@ describe('string params mode', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should handle DATA', function() {
|
it('should handle DATA', function() {
|
||||||
var template = CompilerContext.compile('{{foo @bar}}', { stringParams: true });
|
var template = CompilerContext.compile('{{foo @bar}}', {
|
||||||
|
stringParams: true
|
||||||
|
});
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
foo: function(bar, options) {
|
foo: function(bar, options) {
|
||||||
|
|||||||
+70
-16
@@ -69,7 +69,11 @@ describe('subexpressions', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldCompileTo("{{dash 'abc' (concat a b)}}", [context, helpers], 'abc-ab');
|
shouldCompileTo(
|
||||||
|
"{{dash 'abc' (concat a b)}}",
|
||||||
|
[context, helpers],
|
||||||
|
'abc-ab'
|
||||||
|
);
|
||||||
shouldCompileTo('{{dash d (concat a b)}}', [context, helpers], 'd-ab');
|
shouldCompileTo('{{dash d (concat a b)}}', [context, helpers], 'd-ab');
|
||||||
shouldCompileTo('{{dash c.c (concat a b)}}', [context, helpers], 'c-ab');
|
shouldCompileTo('{{dash c.c (concat a b)}}', [context, helpers], 'c-ab');
|
||||||
shouldCompileTo('{{dash (concat a b) c.c}}', [context, helpers], 'ab-c');
|
shouldCompileTo('{{dash (concat a b) c.c}}', [context, helpers], 'ab-c');
|
||||||
@@ -122,24 +126,36 @@ describe('subexpressions', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('multiple subexpressions in a hash', function() {
|
it('multiple subexpressions in a hash', function() {
|
||||||
var string = '{{input aria-label=(t "Name") placeholder=(t "Example User")}}';
|
var string =
|
||||||
|
'{{input aria-label=(t "Name") placeholder=(t "Example User")}}';
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
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);
|
||||||
return new Handlebars.SafeString('<input aria-label="' + ariaLabel + '" placeholder="' + placeholder + '" />');
|
return new Handlebars.SafeString(
|
||||||
|
'<input aria-label="' +
|
||||||
|
ariaLabel +
|
||||||
|
'" placeholder="' +
|
||||||
|
placeholder +
|
||||||
|
'" />'
|
||||||
|
);
|
||||||
},
|
},
|
||||||
t: function(defaultString) {
|
t: function(defaultString) {
|
||||||
return new Handlebars.SafeString(defaultString);
|
return new Handlebars.SafeString(defaultString);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
shouldCompileTo(string, [{}, helpers], '<input aria-label="Name" placeholder="Example User" />');
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
[{}, helpers],
|
||||||
|
'<input aria-label="Name" placeholder="Example User" />'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('multiple subexpressions in a hash with context', function() {
|
it('multiple subexpressions in a hash with context', function() {
|
||||||
var string = '{{input aria-label=(t item.field) placeholder=(t item.placeholder)}}';
|
var string =
|
||||||
|
'{{input aria-label=(t item.field) placeholder=(t item.placeholder)}}';
|
||||||
|
|
||||||
var context = {
|
var context = {
|
||||||
item: {
|
item: {
|
||||||
@@ -153,44 +169,82 @@ describe('subexpressions', function() {
|
|||||||
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);
|
||||||
return new Handlebars.SafeString('<input aria-label="' + ariaLabel + '" placeholder="' + placeholder + '" />');
|
return new Handlebars.SafeString(
|
||||||
|
'<input aria-label="' +
|
||||||
|
ariaLabel +
|
||||||
|
'" placeholder="' +
|
||||||
|
placeholder +
|
||||||
|
'" />'
|
||||||
|
);
|
||||||
},
|
},
|
||||||
t: function(defaultString) {
|
t: function(defaultString) {
|
||||||
return new Handlebars.SafeString(defaultString);
|
return new Handlebars.SafeString(defaultString);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
shouldCompileTo(string, [context, helpers], '<input aria-label="Name" placeholder="Example User" />');
|
shouldCompileTo(
|
||||||
|
string,
|
||||||
|
[context, helpers],
|
||||||
|
'<input aria-label="Name" placeholder="Example User" />'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('in string params mode,', function() {
|
it('in string params mode,', function() {
|
||||||
var template = CompilerContext.compile('{{snog (blorg foo x=y) yeah a=b}}', {stringParams: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{snog (blorg foo x=y) yeah a=b}}',
|
||||||
|
{ stringParams: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
snog: function(a, b, options) {
|
snog: function(a, b, options) {
|
||||||
equals(a, 'foo');
|
equals(a, 'foo');
|
||||||
equals(options.types.length, 2, 'string params for outer helper processed correctly');
|
equals(
|
||||||
equals(options.types[0], 'SubExpression', 'string params for outer helper processed correctly');
|
options.types.length,
|
||||||
equals(options.types[1], 'PathExpression', 'string params for outer helper processed correctly');
|
2,
|
||||||
|
'string params for outer helper processed correctly'
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
options.types[0],
|
||||||
|
'SubExpression',
|
||||||
|
'string params for outer helper processed correctly'
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
options.types[1],
|
||||||
|
'PathExpression',
|
||||||
|
'string params for outer helper processed correctly'
|
||||||
|
);
|
||||||
return a + b;
|
return a + b;
|
||||||
},
|
},
|
||||||
|
|
||||||
blorg: function(a, options) {
|
blorg: function(a, options) {
|
||||||
equals(options.types.length, 1, 'string params for inner helper processed correctly');
|
equals(
|
||||||
equals(options.types[0], 'PathExpression', 'string params for inner helper processed correctly');
|
options.types.length,
|
||||||
|
1,
|
||||||
|
'string params for inner helper processed correctly'
|
||||||
|
);
|
||||||
|
equals(
|
||||||
|
options.types[0],
|
||||||
|
'PathExpression',
|
||||||
|
'string params for inner helper processed correctly'
|
||||||
|
);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template({
|
var result = template(
|
||||||
|
{
|
||||||
foo: {},
|
foo: {},
|
||||||
yeah: {}
|
yeah: {}
|
||||||
}, {helpers: helpers});
|
},
|
||||||
|
{ helpers: helpers }
|
||||||
|
);
|
||||||
|
|
||||||
equals(result, 'fooyeah');
|
equals(result, 'fooyeah');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('as hashes in string params mode', function() {
|
it('as hashes in string params mode', function() {
|
||||||
var template = CompilerContext.compile('{{blog fun=(bork)}}', {stringParams: true});
|
var template = CompilerContext.compile('{{blog fun=(bork)}}', {
|
||||||
|
stringParams: true
|
||||||
|
});
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
blog: function(options) {
|
blog: function(options) {
|
||||||
|
|||||||
+392
-45
@@ -55,7 +55,16 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
it('supports escaping delimiters', function() {
|
it('supports escaping delimiters', function() {
|
||||||
var result = tokenize('{{foo}} \\{{bar}} {{baz}}');
|
var result = tokenize('{{foo}} \\{{bar}} {{baz}}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
shouldBeToken(result[3], 'CONTENT', ' ');
|
shouldBeToken(result[3], 'CONTENT', ' ');
|
||||||
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
||||||
@@ -63,7 +72,14 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
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, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'CONTENT',
|
||||||
|
'CONTENT'
|
||||||
|
]);
|
||||||
|
|
||||||
shouldBeToken(result[3], 'CONTENT', ' ');
|
shouldBeToken(result[3], 'CONTENT', ' ');
|
||||||
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
||||||
@@ -72,14 +88,35 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
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, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
shouldBeToken(result[4], 'CONTENT', '{{{bar}}} ');
|
shouldBeToken(result[4], 'CONTENT', '{{{bar}}} ');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('supports escaping escape character', function() {
|
it('supports escaping escape character', function() {
|
||||||
var result = tokenize('{{foo}} \\\\{{bar}} {{baz}}');
|
var result = tokenize('{{foo}} \\\\{{bar}} {{baz}}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||||
shouldBeToken(result[5], 'ID', 'bar');
|
shouldBeToken(result[5], 'ID', 'bar');
|
||||||
@@ -87,7 +124,19 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
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, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||||
shouldBeToken(result[5], 'ID', 'bar');
|
shouldBeToken(result[5], 'ID', 'bar');
|
||||||
@@ -97,7 +146,18 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
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, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'CONTENT',
|
||||||
|
'CONTENT'
|
||||||
|
]);
|
||||||
|
|
||||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||||
shouldBeToken(result[4], 'OPEN', '{{');
|
shouldBeToken(result[4], 'OPEN', '{{');
|
||||||
@@ -108,7 +168,17 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
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, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'CONTENT',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
||||||
shouldBeToken(result[5], 'CONTENT', '\\');
|
shouldBeToken(result[5], 'CONTENT', '\\');
|
||||||
@@ -118,7 +188,19 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
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, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN_UNESCAPED', 'ID', 'CLOSE_UNESCAPED', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN_UNESCAPED',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_UNESCAPED',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||||
shouldBeToken(result[5], 'ID', 'bar');
|
shouldBeToken(result[5], 'ID', 'bar');
|
||||||
@@ -133,7 +215,15 @@ describe('Tokenizer', 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']);
|
||||||
|
|
||||||
shouldMatchTokens(tokenize('{{foo.bar.baz}}'), ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
|
shouldMatchTokens(tokenize('{{foo.bar.baz}}'), [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'SEP',
|
||||||
|
'ID',
|
||||||
|
'SEP',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows path literals with []', function() {
|
it('allows path literals with []', function() {
|
||||||
@@ -143,7 +233,18 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
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, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE', 'OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'SEP',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'SEP',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows escaped literals in []', function() {
|
it('allows escaped literals in []', function() {
|
||||||
@@ -158,13 +259,29 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
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, ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'SEP',
|
||||||
|
'ID',
|
||||||
|
'SEP',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
shouldBeToken(result[1], 'ID', '..');
|
shouldBeToken(result[1], 'ID', '..');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tokenizes a path with .. as a parent path', function() {
|
it('tokenizes a path with .. as a parent path', function() {
|
||||||
var result = tokenize('{{../foo.bar}}');
|
var result = tokenize('{{../foo.bar}}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'SEP',
|
||||||
|
'ID',
|
||||||
|
'SEP',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
shouldBeToken(result[1], 'ID', '..');
|
shouldBeToken(result[1], 'ID', '..');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -216,7 +333,15 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
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, ['OPEN_PARTIAL', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN_PARTIAL',
|
||||||
|
'ID',
|
||||||
|
'SEP',
|
||||||
|
'ID',
|
||||||
|
'SEP',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tokenizes partial block declarations', function() {
|
it('tokenizes partial block declarations', function() {
|
||||||
@@ -225,34 +350,69 @@ describe('Tokenizer', function() {
|
|||||||
});
|
});
|
||||||
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, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'CONTENT',
|
||||||
|
'COMMENT',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
shouldBeToken(result[1], 'COMMENT', '{{! this is a comment }}');
|
shouldBeToken(result[1], 'COMMENT', '{{! this is a comment }}');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tokenizes a block comment as "COMMENT"', function() {
|
it('tokenizes a block comment as "COMMENT"', function() {
|
||||||
var result = tokenize('foo {{!-- this is a {{comment}} --}} bar {{ baz }}');
|
var result = tokenize('foo {{!-- this is a {{comment}} --}} bar {{ baz }}');
|
||||||
shouldMatchTokens(result, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'CONTENT',
|
||||||
|
'COMMENT',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
shouldBeToken(result[1], 'COMMENT', '{{!-- this is a {{comment}} --}}');
|
shouldBeToken(result[1], 'COMMENT', '{{!-- this is a {{comment}} --}}');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tokenizes a block comment with whitespace as "COMMENT"', function() {
|
it('tokenizes a block comment with whitespace as "COMMENT"', function() {
|
||||||
var result = tokenize('foo {{!-- this is a\n{{comment}}\n--}} bar {{ baz }}');
|
var result = tokenize(
|
||||||
shouldMatchTokens(result, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
|
'foo {{!-- this is a\n{{comment}}\n--}} bar {{ baz }}'
|
||||||
|
);
|
||||||
|
shouldMatchTokens(result, [
|
||||||
|
'CONTENT',
|
||||||
|
'COMMENT',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
shouldBeToken(result[1], 'COMMENT', '{{!-- this is a\n{{comment}}\n--}}');
|
shouldBeToken(result[1], 'COMMENT', '{{!-- this is a\n{{comment}}\n--}}');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tokenizes open and closing blocks as OPEN_BLOCK, ID, CLOSE ..., OPEN_ENDBLOCK ID CLOSE', function() {
|
it('tokenizes open and closing blocks as OPEN_BLOCK, ID, CLOSE ..., OPEN_ENDBLOCK ID CLOSE', function() {
|
||||||
var result = tokenize('{{#foo}}content{{/foo}}');
|
var result = tokenize('{{#foo}}content{{/foo}}');
|
||||||
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'CLOSE', 'CONTENT', 'OPEN_ENDBLOCK', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN_BLOCK',
|
||||||
|
'ID',
|
||||||
|
'CLOSE',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN_ENDBLOCK',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tokenizes directives', function() {
|
it('tokenizes directives', function() {
|
||||||
shouldMatchTokens(
|
shouldMatchTokens(tokenize('{{#*foo}}content{{/foo}}'), [
|
||||||
tokenize('{{#*foo}}content{{/foo}}'),
|
'OPEN_BLOCK',
|
||||||
['OPEN_BLOCK', 'ID', 'CLOSE', 'CONTENT', 'OPEN_ENDBLOCK', 'ID', 'CLOSE']);
|
'ID',
|
||||||
shouldMatchTokens(
|
'CLOSE',
|
||||||
tokenize('{{*foo}}'),
|
'CONTENT',
|
||||||
['OPEN', 'ID', 'CLOSE']);
|
'OPEN_ENDBLOCK',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
shouldMatchTokens(tokenize('{{*foo}}'), ['OPEN', 'ID', 'CLOSE']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tokenizes inverse sections as "INVERSE"', function() {
|
it('tokenizes inverse sections as "INVERSE"', function() {
|
||||||
@@ -351,28 +511,98 @@ describe('Tokenizer', function() {
|
|||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
|
||||||
|
|
||||||
result = tokenize('{{ foo bar baz=bat }}');
|
result = tokenize('{{ foo bar baz=bat }}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'EQUALS',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
result = tokenize('{{ foo bar baz=1 }}');
|
result = tokenize('{{ foo bar baz=1 }}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'NUMBER', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'EQUALS',
|
||||||
|
'NUMBER',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
result = tokenize('{{ foo bar baz=true }}');
|
result = tokenize('{{ foo bar baz=true }}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'BOOLEAN', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'EQUALS',
|
||||||
|
'BOOLEAN',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
result = tokenize('{{ foo bar baz=false }}');
|
result = tokenize('{{ foo bar baz=false }}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'BOOLEAN', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'EQUALS',
|
||||||
|
'BOOLEAN',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
result = tokenize('{{ foo bar\n baz=bat }}');
|
result = tokenize('{{ foo bar\n baz=bat }}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'EQUALS',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
result = tokenize('{{ foo bar baz="bat" }}');
|
result = tokenize('{{ foo bar baz="bat" }}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'STRING', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'EQUALS',
|
||||||
|
'STRING',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
result = tokenize('{{ foo bar baz="bat" bam=wot }}');
|
result = tokenize('{{ foo bar baz="bat" bam=wot }}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'STRING', 'ID', 'EQUALS', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'EQUALS',
|
||||||
|
'STRING',
|
||||||
|
'ID',
|
||||||
|
'EQUALS',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
result = tokenize('{{foo omg bar=baz bat="bam"}}');
|
result = tokenize('{{foo omg bar=baz bat="bam"}}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'ID', 'EQUALS', 'STRING', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'EQUALS',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'EQUALS',
|
||||||
|
'STRING',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
shouldBeToken(result[2], 'ID', 'omg');
|
shouldBeToken(result[2], 'ID', 'omg');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -386,7 +616,15 @@ describe('Tokenizer', function() {
|
|||||||
shouldBeToken(result[3], 'ID', 'bar');
|
shouldBeToken(result[3], 'ID', 'bar');
|
||||||
|
|
||||||
result = tokenize('{{ foo bar=@baz }}');
|
result = tokenize('{{ foo bar=@baz }}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'DATA', 'ID', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'EQUALS',
|
||||||
|
'DATA',
|
||||||
|
'ID',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
shouldBeToken(result[5], 'ID', 'baz');
|
shouldBeToken(result[5], 'ID', 'baz');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -400,12 +638,27 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
it('tokenizes subexpressions', function() {
|
it('tokenizes subexpressions', function() {
|
||||||
var result = tokenize('{{foo (bar)}}');
|
var result = tokenize('{{foo (bar)}}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'CLOSE_SEXPR', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'OPEN_SEXPR',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_SEXPR',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
shouldBeToken(result[1], 'ID', 'foo');
|
shouldBeToken(result[1], 'ID', 'foo');
|
||||||
shouldBeToken(result[3], 'ID', 'bar');
|
shouldBeToken(result[3], 'ID', 'bar');
|
||||||
|
|
||||||
result = tokenize('{{foo (a-x b-y)}}');
|
result = tokenize('{{foo (a-x b-y)}}');
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'ID', 'CLOSE_SEXPR', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'OPEN_SEXPR',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_SEXPR',
|
||||||
|
'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');
|
||||||
@@ -413,7 +666,21 @@ describe('Tokenizer', function() {
|
|||||||
|
|
||||||
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, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'OPEN_SEXPR', 'ID', 'ID', 'CLOSE_SEXPR', 'CLOSE_SEXPR', 'OPEN_SEXPR', 'ID', 'CLOSE_SEXPR', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'OPEN_SEXPR',
|
||||||
|
'ID',
|
||||||
|
'OPEN_SEXPR',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_SEXPR',
|
||||||
|
'CLOSE_SEXPR',
|
||||||
|
'OPEN_SEXPR',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_SEXPR',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
shouldBeToken(result[3], 'ID', 'bar');
|
shouldBeToken(result[3], 'ID', 'bar');
|
||||||
shouldBeToken(result[5], 'ID', 'lol');
|
shouldBeToken(result[5], 'ID', 'lol');
|
||||||
shouldBeToken(result[6], 'ID', 'rofl');
|
shouldBeToken(result[6], 'ID', 'rofl');
|
||||||
@@ -421,29 +688,109 @@ describe('Tokenizer', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('tokenizes nested subexpressions: literals', function() {
|
it('tokenizes nested subexpressions: literals', function() {
|
||||||
var result = tokenize("{{foo (bar (lol true) false) (baz 1) (blah 'b') (blorg \"c\")}}");
|
var result = tokenize(
|
||||||
shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'OPEN_SEXPR', 'ID', 'BOOLEAN', 'CLOSE_SEXPR', 'BOOLEAN', 'CLOSE_SEXPR', 'OPEN_SEXPR', 'ID', 'NUMBER', 'CLOSE_SEXPR', 'OPEN_SEXPR', 'ID', 'STRING', 'CLOSE_SEXPR', 'OPEN_SEXPR', 'ID', 'STRING', 'CLOSE_SEXPR', 'CLOSE']);
|
'{{foo (bar (lol true) false) (baz 1) (blah \'b\') (blorg "c")}}'
|
||||||
|
);
|
||||||
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN',
|
||||||
|
'ID',
|
||||||
|
'OPEN_SEXPR',
|
||||||
|
'ID',
|
||||||
|
'OPEN_SEXPR',
|
||||||
|
'ID',
|
||||||
|
'BOOLEAN',
|
||||||
|
'CLOSE_SEXPR',
|
||||||
|
'BOOLEAN',
|
||||||
|
'CLOSE_SEXPR',
|
||||||
|
'OPEN_SEXPR',
|
||||||
|
'ID',
|
||||||
|
'NUMBER',
|
||||||
|
'CLOSE_SEXPR',
|
||||||
|
'OPEN_SEXPR',
|
||||||
|
'ID',
|
||||||
|
'STRING',
|
||||||
|
'CLOSE_SEXPR',
|
||||||
|
'OPEN_SEXPR',
|
||||||
|
'ID',
|
||||||
|
'STRING',
|
||||||
|
'CLOSE_SEXPR',
|
||||||
|
'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, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN_BLOCK',
|
||||||
|
'ID',
|
||||||
|
'OPEN_BLOCK_PARAMS',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_BLOCK_PARAMS',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
result = tokenize('{{#foo as |bar baz|}}');
|
result = tokenize('{{#foo as |bar baz|}}');
|
||||||
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN_BLOCK',
|
||||||
|
'ID',
|
||||||
|
'OPEN_BLOCK_PARAMS',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_BLOCK_PARAMS',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
result = tokenize('{{#foo as | bar baz |}}');
|
result = tokenize('{{#foo as | bar baz |}}');
|
||||||
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN_BLOCK',
|
||||||
|
'ID',
|
||||||
|
'OPEN_BLOCK_PARAMS',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_BLOCK_PARAMS',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
result = tokenize('{{#foo as as | bar baz |}}');
|
result = tokenize('{{#foo as as | bar baz |}}');
|
||||||
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN_BLOCK',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'OPEN_BLOCK_PARAMS',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_BLOCK_PARAMS',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
|
|
||||||
result = tokenize('{{else foo as |bar baz|}}');
|
result = tokenize('{{else foo as |bar baz|}}');
|
||||||
shouldMatchTokens(result, ['OPEN_INVERSE_CHAIN', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN_INVERSE_CHAIN',
|
||||||
|
'ID',
|
||||||
|
'OPEN_BLOCK_PARAMS',
|
||||||
|
'ID',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_BLOCK_PARAMS',
|
||||||
|
'CLOSE'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tokenizes raw blocks', function() {
|
it('tokenizes raw blocks', function() {
|
||||||
var result = tokenize('{{{{a}}}} abc {{{{/a}}}} aaa {{{{a}}}} abc {{{{/a}}}}');
|
var result = tokenize(
|
||||||
shouldMatchTokens(result, ['OPEN_RAW_BLOCK', 'ID', 'CLOSE_RAW_BLOCK', 'CONTENT', 'END_RAW_BLOCK', 'CONTENT', 'OPEN_RAW_BLOCK', 'ID', 'CLOSE_RAW_BLOCK', 'CONTENT', 'END_RAW_BLOCK']);
|
'{{{{a}}}} abc {{{{/a}}}} aaa {{{{a}}}} abc {{{{/a}}}}'
|
||||||
|
);
|
||||||
|
shouldMatchTokens(result, [
|
||||||
|
'OPEN_RAW_BLOCK',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_RAW_BLOCK',
|
||||||
|
'CONTENT',
|
||||||
|
'END_RAW_BLOCK',
|
||||||
|
'CONTENT',
|
||||||
|
'OPEN_RAW_BLOCK',
|
||||||
|
'ID',
|
||||||
|
'CLOSE_RAW_BLOCK',
|
||||||
|
'CONTENT',
|
||||||
|
'END_RAW_BLOCK'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+240
-50
@@ -19,35 +19,67 @@ describe('track ids', function() {
|
|||||||
equals(template({}, { helpers: helpers }), 'success');
|
equals(template({}, { helpers: helpers }), 'success');
|
||||||
});
|
});
|
||||||
it('should include argument ids', function() {
|
it('should include argument ids', function() {
|
||||||
var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {trackIds: true});
|
var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {
|
||||||
|
trackIds: true
|
||||||
|
});
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
wycats: function(passiveVoice, noun, options) {
|
wycats: function(passiveVoice, noun, options) {
|
||||||
equal(options.ids[0], 'is.a');
|
equal(options.ids[0], 'is.a');
|
||||||
equal(options.ids[1], 'slave.driver');
|
equal(options.ids[1], 'slave.driver');
|
||||||
|
|
||||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
return (
|
||||||
|
'HELP ME MY BOSS ' +
|
||||||
|
options.ids[0] +
|
||||||
|
':' +
|
||||||
|
passiveVoice +
|
||||||
|
' ' +
|
||||||
|
options.ids[1] +
|
||||||
|
':' +
|
||||||
|
noun
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS is.a:foo slave.driver:bar');
|
equals(
|
||||||
|
template(context, { helpers: helpers }),
|
||||||
|
'HELP ME MY BOSS is.a:foo slave.driver:bar'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should include hash ids', function() {
|
it('should include hash ids', function() {
|
||||||
var template = CompilerContext.compile('{{wycats bat=is.a baz=slave.driver}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{wycats bat=is.a baz=slave.driver}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
wycats: function(options) {
|
wycats: function(options) {
|
||||||
equal(options.hashIds.bat, 'is.a');
|
equal(options.hashIds.bat, 'is.a');
|
||||||
equal(options.hashIds.baz, 'slave.driver');
|
equal(options.hashIds.baz, 'slave.driver');
|
||||||
|
|
||||||
return 'HELP ME MY BOSS ' + options.hashIds.bat + ':' + options.hash.bat + ' ' + options.hashIds.baz + ':' + options.hash.baz;
|
return (
|
||||||
|
'HELP ME MY BOSS ' +
|
||||||
|
options.hashIds.bat +
|
||||||
|
':' +
|
||||||
|
options.hash.bat +
|
||||||
|
' ' +
|
||||||
|
options.hashIds.baz +
|
||||||
|
':' +
|
||||||
|
options.hash.baz
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS is.a:foo slave.driver:bar');
|
equals(
|
||||||
|
template(context, { helpers: helpers }),
|
||||||
|
'HELP ME MY BOSS is.a:foo slave.driver:bar'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should note ../ and ./ references', function() {
|
it('should note ../ and ./ references', function() {
|
||||||
var template = CompilerContext.compile('{{wycats ./is.a ../slave.driver this.is.a this}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{wycats ./is.a ../slave.driver this.is.a this}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
wycats: function(passiveVoice, noun, thiz, thiz2, options) {
|
wycats: function(passiveVoice, noun, thiz, thiz2, options) {
|
||||||
@@ -56,29 +88,57 @@ describe('track ids', function() {
|
|||||||
equal(options.ids[2], 'is.a');
|
equal(options.ids[2], 'is.a');
|
||||||
equal(options.ids[3], '');
|
equal(options.ids[3], '');
|
||||||
|
|
||||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
return (
|
||||||
|
'HELP ME MY BOSS ' +
|
||||||
|
options.ids[0] +
|
||||||
|
':' +
|
||||||
|
passiveVoice +
|
||||||
|
' ' +
|
||||||
|
options.ids[1] +
|
||||||
|
':' +
|
||||||
|
noun
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS is.a:foo ../slave.driver:undefined');
|
equals(
|
||||||
|
template(context, { helpers: helpers }),
|
||||||
|
'HELP ME MY BOSS is.a:foo ../slave.driver:undefined'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should note @data references', function() {
|
it('should note @data references', function() {
|
||||||
var template = CompilerContext.compile('{{wycats @is.a @slave.driver}}', {trackIds: true});
|
var template = CompilerContext.compile('{{wycats @is.a @slave.driver}}', {
|
||||||
|
trackIds: true
|
||||||
|
});
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
wycats: function(passiveVoice, noun, options) {
|
wycats: function(passiveVoice, noun, options) {
|
||||||
equal(options.ids[0], '@is.a');
|
equal(options.ids[0], '@is.a');
|
||||||
equal(options.ids[1], '@slave.driver');
|
equal(options.ids[1], '@slave.driver');
|
||||||
|
|
||||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
return (
|
||||||
|
'HELP ME MY BOSS ' +
|
||||||
|
options.ids[0] +
|
||||||
|
':' +
|
||||||
|
passiveVoice +
|
||||||
|
' ' +
|
||||||
|
options.ids[1] +
|
||||||
|
':' +
|
||||||
|
noun
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
equals(template({}, {helpers: helpers, data: context}), 'HELP ME MY BOSS @is.a:foo @slave.driver:bar');
|
equals(
|
||||||
|
template({}, { helpers: helpers, data: context }),
|
||||||
|
'HELP ME MY BOSS @is.a:foo @slave.driver:bar'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return null for constants', function() {
|
it('should return null for constants', function() {
|
||||||
var template = CompilerContext.compile('{{wycats 1 "foo" key=false}}', {trackIds: true});
|
var template = CompilerContext.compile('{{wycats 1 "foo" key=false}}', {
|
||||||
|
trackIds: true
|
||||||
|
});
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
wycats: function(passiveVoice, noun, options) {
|
wycats: function(passiveVoice, noun, options) {
|
||||||
@@ -86,17 +146,31 @@ describe('track ids', function() {
|
|||||||
equal(options.ids[1], null);
|
equal(options.ids[1], null);
|
||||||
equal(options.hashIds.key, null);
|
equal(options.hashIds.key, null);
|
||||||
|
|
||||||
return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun + ' ' + options.hash.key;
|
return (
|
||||||
|
'HELP ME MY BOSS ' +
|
||||||
|
passiveVoice +
|
||||||
|
' ' +
|
||||||
|
noun +
|
||||||
|
' ' +
|
||||||
|
options.hash.key
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS 1 foo false');
|
equals(
|
||||||
|
template(context, { helpers: helpers }),
|
||||||
|
'HELP ME MY BOSS 1 foo false'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should return true for subexpressions', function() {
|
it('should return true for subexpressions', function() {
|
||||||
var template = CompilerContext.compile('{{wycats (sub)}}', {trackIds: true});
|
var template = CompilerContext.compile('{{wycats (sub)}}', {
|
||||||
|
trackIds: true
|
||||||
|
});
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
sub: function() { return 1; },
|
sub: function() {
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
wycats: function(passiveVoice, options) {
|
wycats: function(passiveVoice, options) {
|
||||||
equal(options.ids[0], true);
|
equal(options.ids[0], true);
|
||||||
|
|
||||||
@@ -108,7 +182,10 @@ describe('track ids', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should use block param paths', function() {
|
it('should use block param paths', function() {
|
||||||
var template = CompilerContext.compile('{{#doIt as |is|}}{{wycats is.a slave.driver is}}{{/doIt}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#doIt as |is|}}{{wycats is.a slave.driver is}}{{/doIt}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
var helpers = {
|
var helpers = {
|
||||||
doIt: function(options) {
|
doIt: function(options) {
|
||||||
@@ -121,11 +198,23 @@ describe('track ids', function() {
|
|||||||
equal(options.ids[1], 'slave.driver');
|
equal(options.ids[1], 'slave.driver');
|
||||||
equal(options.ids[2], 'zomg');
|
equal(options.ids[2], 'zomg');
|
||||||
|
|
||||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
return (
|
||||||
|
'HELP ME MY BOSS ' +
|
||||||
|
options.ids[0] +
|
||||||
|
':' +
|
||||||
|
passiveVoice +
|
||||||
|
' ' +
|
||||||
|
options.ids[1] +
|
||||||
|
':' +
|
||||||
|
noun
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS zomg.a:foo slave.driver:bar');
|
equals(
|
||||||
|
template(context, { helpers: helpers }),
|
||||||
|
'HELP ME MY BOSS zomg.a:foo slave.driver:bar'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('builtin helpers', function() {
|
describe('builtin helpers', function() {
|
||||||
@@ -140,53 +229,119 @@ describe('track ids', function() {
|
|||||||
|
|
||||||
describe('#each', function() {
|
describe('#each', function() {
|
||||||
it('should track contextPath for arrays', function() {
|
it('should track contextPath for arrays', function() {
|
||||||
var template = CompilerContext.compile('{{#each array}}{{wycats name}}{{/each}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#each array}}{{wycats name}}{{/each}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:array.0\nbar:array.1\n');
|
equals(
|
||||||
|
template(
|
||||||
|
{ array: [{ name: 'foo' }, { name: 'bar' }] },
|
||||||
|
{ helpers: helpers }
|
||||||
|
),
|
||||||
|
'foo:array.0\nbar:array.1\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should track contextPath for keys', function() {
|
it('should track contextPath for keys', function() {
|
||||||
var template = CompilerContext.compile('{{#each object}}{{wycats name}}{{/each}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#each object}}{{wycats name}}{{/each}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
equals(template({object: {foo: {name: 'foo'}, bar: {name: 'bar'}}}, {helpers: helpers}), 'foo:object.foo\nbar:object.bar\n');
|
equals(
|
||||||
|
template(
|
||||||
|
{ object: { foo: { name: 'foo' }, bar: { name: 'bar' } } },
|
||||||
|
{ helpers: helpers }
|
||||||
|
),
|
||||||
|
'foo:object.foo\nbar:object.bar\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should handle nesting', function() {
|
it('should handle nesting', function() {
|
||||||
var template = CompilerContext.compile('{{#each .}}{{#each .}}{{wycats name}}{{/each}}{{/each}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#each .}}{{#each .}}{{wycats name}}{{/each}}{{/each}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:.array..0\nbar:.array..1\n');
|
equals(
|
||||||
|
template(
|
||||||
|
{ array: [{ name: 'foo' }, { name: 'bar' }] },
|
||||||
|
{ helpers: helpers }
|
||||||
|
),
|
||||||
|
'foo:.array..0\nbar:.array..1\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should handle block params', function() {
|
it('should handle block params', function() {
|
||||||
var template = CompilerContext.compile('{{#each array as |value|}}{{blockParams value.name}}{{/each}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#each array as |value|}}{{blockParams value.name}}{{/each}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:array.0.name\nbar:array.1.name\n');
|
equals(
|
||||||
|
template(
|
||||||
|
{ array: [{ name: 'foo' }, { name: 'bar' }] },
|
||||||
|
{ helpers: helpers }
|
||||||
|
),
|
||||||
|
'foo:array.0.name\nbar:array.1.name\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#with', function() {
|
describe('#with', function() {
|
||||||
it('should track contextPath', function() {
|
it('should track contextPath', function() {
|
||||||
var template = CompilerContext.compile('{{#with field}}{{wycats name}}{{/with}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#with field}}{{wycats name}}{{/with}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
equals(template({field: {name: 'foo'}}, {helpers: helpers}), 'foo:field\n');
|
equals(
|
||||||
|
template({ field: { name: 'foo' } }, { helpers: helpers }),
|
||||||
|
'foo:field\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should handle nesting', function() {
|
it('should handle nesting', function() {
|
||||||
var template = CompilerContext.compile('{{#with bat}}{{#with field}}{{wycats name}}{{/with}}{{/with}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#with bat}}{{#with field}}{{wycats name}}{{/with}}{{/with}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
equals(template({bat: {field: {name: 'foo'}}}, {helpers: helpers}), 'foo:bat.field\n');
|
equals(
|
||||||
|
template({ bat: { field: { name: 'foo' } } }, { helpers: helpers }),
|
||||||
|
'foo:bat.field\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#blockHelperMissing', function() {
|
describe('#blockHelperMissing', function() {
|
||||||
it('should track contextPath for arrays', function() {
|
it('should track contextPath for arrays', function() {
|
||||||
var template = CompilerContext.compile('{{#field}}{{wycats name}}{{/field}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#field}}{{wycats name}}{{/field}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
equals(template({field: [{name: 'foo'}]}, {helpers: helpers}), 'foo:field.0\n');
|
equals(
|
||||||
|
template({ field: [{ name: 'foo' }] }, { helpers: helpers }),
|
||||||
|
'foo:field.0\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should track contextPath for keys', function() {
|
it('should track contextPath for keys', function() {
|
||||||
var template = CompilerContext.compile('{{#field}}{{wycats name}}{{/field}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#field}}{{wycats name}}{{/field}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
equals(template({field: {name: 'foo'}}, {helpers: helpers}), 'foo:field\n');
|
equals(
|
||||||
|
template({ field: { name: 'foo' } }, { helpers: helpers }),
|
||||||
|
'foo:field\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should handle nesting', function() {
|
it('should handle nesting', function() {
|
||||||
var template = CompilerContext.compile('{{#bat}}{{#field}}{{wycats name}}{{/field}}{{/bat}}', {trackIds: true});
|
var template = CompilerContext.compile(
|
||||||
|
'{{#bat}}{{#field}}{{wycats name}}{{/field}}{{/bat}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
);
|
||||||
|
|
||||||
equals(template({bat: {field: {name: 'foo'}}}, {helpers: helpers}), 'foo:bat.field\n');
|
equals(
|
||||||
|
template({ bat: { field: { name: 'foo' } } }, { helpers: helpers }),
|
||||||
|
'foo:bat.field\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -202,36 +357,71 @@ describe('track ids', function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it('should pass track id for basic partial', function() {
|
it('should pass track id for basic partial', function() {
|
||||||
var template = CompilerContext.compile('Dudes: {{#dudes}}{{> dude}}{{/dudes}}', {trackIds: true}),
|
var template = CompilerContext.compile(
|
||||||
hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
'Dudes: {{#dudes}}{{> dude}}{{/dudes}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
),
|
||||||
|
hash = {
|
||||||
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
var partials = {
|
var partials = {
|
||||||
dude: CompilerContext.compile('{{wycats name}}', { trackIds: true })
|
dude: CompilerContext.compile('{{wycats name}}', { trackIds: true })
|
||||||
};
|
};
|
||||||
|
|
||||||
equals(template(hash, {helpers: helpers, partials: partials}), 'Dudes: Yehuda:dudes.0\nAlan:dudes.1\n');
|
equals(
|
||||||
|
template(hash, { helpers: helpers, partials: partials }),
|
||||||
|
'Dudes: Yehuda:dudes.0\nAlan:dudes.1\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pass track id for context partial', function() {
|
it('should pass track id for context partial', function() {
|
||||||
var template = CompilerContext.compile('Dudes: {{> dude dudes}}', {trackIds: true}),
|
var template = CompilerContext.compile('Dudes: {{> dude dudes}}', {
|
||||||
hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
trackIds: true
|
||||||
|
}),
|
||||||
var partials = {
|
hash = {
|
||||||
dude: CompilerContext.compile('{{#each this}}{{wycats name}}{{/each}}', {trackIds: true})
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
equals(template(hash, {helpers: helpers, partials: partials}), 'Dudes: Yehuda:dudes..0\nAlan:dudes..1\n');
|
var partials = {
|
||||||
|
dude: CompilerContext.compile(
|
||||||
|
'{{#each this}}{{wycats name}}{{/each}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
equals(
|
||||||
|
template(hash, { helpers: helpers, partials: partials }),
|
||||||
|
'Dudes: Yehuda:dudes..0\nAlan:dudes..1\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should invalidate context for partials with parameters', function() {
|
it('should invalidate context for partials with parameters', function() {
|
||||||
var template = CompilerContext.compile('Dudes: {{#dudes}}{{> dude . bar="foo"}}{{/dudes}}', {trackIds: true}),
|
var template = CompilerContext.compile(
|
||||||
hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
'Dudes: {{#dudes}}{{> dude . bar="foo"}}{{/dudes}}',
|
||||||
|
{ trackIds: true }
|
||||||
|
),
|
||||||
|
hash = {
|
||||||
|
dudes: [
|
||||||
|
{ name: 'Yehuda', url: 'http://yehuda' },
|
||||||
|
{ name: 'Alan', url: 'http://alan' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
var partials = {
|
var partials = {
|
||||||
dude: CompilerContext.compile('{{wycats name}}', { trackIds: true })
|
dude: CompilerContext.compile('{{wycats name}}', { trackIds: true })
|
||||||
};
|
};
|
||||||
|
|
||||||
equals(template(hash, {helpers: helpers, partials: partials}), 'Dudes: Yehuda:true\nAlan:true\n');
|
equals(
|
||||||
|
template(hash, { helpers: helpers, partials: partials }),
|
||||||
|
'Dudes: Yehuda:true\nAlan:true\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+14
-3
@@ -5,19 +5,30 @@ describe('utils', function() {
|
|||||||
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');
|
||||||
}
|
}
|
||||||
equals(safe.toString(), 'testing 1, 2, 3', 'SafeString is equivalent to its underlying string');
|
equals(
|
||||||
|
safe.toString(),
|
||||||
|
'testing 1, 2, 3',
|
||||||
|
'SafeString is equivalent to its underlying string'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('it should not escape SafeString properties', function() {
|
it('it should not escape SafeString properties', function() {
|
||||||
var name = new Handlebars.SafeString('<em>Sean O'Malley</em>');
|
var name = new Handlebars.SafeString('<em>Sean O'Malley</em>');
|
||||||
|
|
||||||
shouldCompileTo('{{name}}', [{name: name}], '<em>Sean O'Malley</em>');
|
shouldCompileTo(
|
||||||
|
'{{name}}',
|
||||||
|
[{ name: name }],
|
||||||
|
'<em>Sean O'Malley</em>'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#escapeExpression', function() {
|
describe('#escapeExpression', function() {
|
||||||
it('shouhld escape html', function() {
|
it('shouhld escape html', function() {
|
||||||
equals(Handlebars.Utils.escapeExpression('foo<&"\'>'), 'foo<&"'>');
|
equals(
|
||||||
|
Handlebars.Utils.escapeExpression('foo<&"\'>'),
|
||||||
|
'foo<&"'>'
|
||||||
|
);
|
||||||
equals(Handlebars.Utils.escapeExpression('foo='), 'foo=');
|
equals(Handlebars.Utils.escapeExpression('foo='), 'foo=');
|
||||||
});
|
});
|
||||||
it('should not escape SafeString', function() {
|
it('should not escape SafeString', function() {
|
||||||
|
|||||||
+30
-8
@@ -7,7 +7,11 @@ describe('Visitor', function() {
|
|||||||
// Simply run the thing and make sure it does not fail and that all of the
|
// Simply run the thing and make sure it does not fail and that all of the
|
||||||
// stub methods are executed
|
// stub methods are executed
|
||||||
var visitor = new Handlebars.Visitor();
|
var visitor = new Handlebars.Visitor();
|
||||||
visitor.accept(Handlebars.parse('{{foo}}{{#foo (bar 1 "1" true undefined null) foo=@data}}{{!comment}}{{> bar }} {{/foo}}'));
|
visitor.accept(
|
||||||
|
Handlebars.parse(
|
||||||
|
'{{foo}}{{#foo (bar 1 "1" true undefined null) foo=@data}}{{!comment}}{{> bar }} {{/foo}}'
|
||||||
|
)
|
||||||
|
);
|
||||||
visitor.accept(Handlebars.parse('{{#> bar }} {{/bar}}'));
|
visitor.accept(Handlebars.parse('{{#> bar }} {{/bar}}'));
|
||||||
visitor.accept(Handlebars.parse('{{#* bar }} {{/bar}}'));
|
visitor.accept(Handlebars.parse('{{#* bar }} {{/bar}}'));
|
||||||
visitor.accept(Handlebars.parse('{{* bar }}'));
|
visitor.accept(Handlebars.parse('{{* bar }}'));
|
||||||
@@ -40,7 +44,11 @@ describe('Visitor', function() {
|
|||||||
equal(comment.value, 'comment');
|
equal(comment.value, 'comment');
|
||||||
};
|
};
|
||||||
|
|
||||||
visitor.accept(Handlebars.parse('{{#foo.bar (foo.bar 1 "2" true) foo=@foo.bar}}{{!comment}}{{> bar }} {{/foo.bar}}'));
|
visitor.accept(
|
||||||
|
Handlebars.parse(
|
||||||
|
'{{#foo.bar (foo.bar 1 "2" true) foo=@foo.bar}}{{!comment}}{{> bar }} {{/foo.bar}}'
|
||||||
|
)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('mutating', function() {
|
describe('mutating', function() {
|
||||||
@@ -55,7 +63,10 @@ describe('Visitor', function() {
|
|||||||
|
|
||||||
var ast = Handlebars.parse('{{foo foo="foo"}}');
|
var ast = Handlebars.parse('{{foo foo="foo"}}');
|
||||||
visitor.accept(ast);
|
visitor.accept(ast);
|
||||||
equals(Handlebars.print(ast), '{{ PATH:foo [] HASH{foo=NUMBER{42}} }}\n');
|
equals(
|
||||||
|
Handlebars.print(ast),
|
||||||
|
'{{ PATH:foo [] HASH{foo=NUMBER{42}} }}\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should treat undefined resonse as identity', function() {
|
it('should treat undefined resonse as identity', function() {
|
||||||
var visitor = new Handlebars.Visitor();
|
var visitor = new Handlebars.Visitor();
|
||||||
@@ -63,7 +74,10 @@ describe('Visitor', function() {
|
|||||||
|
|
||||||
var ast = Handlebars.parse('{{foo foo=42}}');
|
var ast = Handlebars.parse('{{foo foo=42}}');
|
||||||
visitor.accept(ast);
|
visitor.accept(ast);
|
||||||
equals(Handlebars.print(ast), '{{ PATH:foo [] HASH{foo=NUMBER{42}} }}\n');
|
equals(
|
||||||
|
Handlebars.print(ast),
|
||||||
|
'{{ PATH:foo [] HASH{foo=NUMBER{42}} }}\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should remove false responses', function() {
|
it('should remove false responses', function() {
|
||||||
var visitor = new Handlebars.Visitor();
|
var visitor = new Handlebars.Visitor();
|
||||||
@@ -78,7 +92,8 @@ describe('Visitor', function() {
|
|||||||
equals(Handlebars.print(ast), '{{ PATH:foo [] }}\n');
|
equals(Handlebars.print(ast), '{{ PATH:foo [] }}\n');
|
||||||
});
|
});
|
||||||
it('should throw when removing required values', function() {
|
it('should throw when removing required values', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
var visitor = new Handlebars.Visitor();
|
var visitor = new Handlebars.Visitor();
|
||||||
|
|
||||||
visitor.mutating = true;
|
visitor.mutating = true;
|
||||||
@@ -88,10 +103,14 @@ describe('Visitor', function() {
|
|||||||
|
|
||||||
var ast = Handlebars.parse('{{foo 42}}');
|
var ast = Handlebars.parse('{{foo 42}}');
|
||||||
visitor.accept(ast);
|
visitor.accept(ast);
|
||||||
}, Handlebars.Exception, 'MustacheStatement requires path');
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'MustacheStatement requires path'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should throw when returning non-node responses', function() {
|
it('should throw when returning non-node responses', function() {
|
||||||
shouldThrow(function() {
|
shouldThrow(
|
||||||
|
function() {
|
||||||
var visitor = new Handlebars.Visitor();
|
var visitor = new Handlebars.Visitor();
|
||||||
|
|
||||||
visitor.mutating = true;
|
visitor.mutating = true;
|
||||||
@@ -101,7 +120,10 @@ describe('Visitor', function() {
|
|||||||
|
|
||||||
var ast = Handlebars.parse('{{foo 42}}');
|
var ast = Handlebars.parse('{{foo 42}}');
|
||||||
visitor.accept(ast);
|
visitor.accept(ast);
|
||||||
}, Handlebars.Exception, 'Unexpected node type "undefined" found when accepting path on MustacheStatement');
|
},
|
||||||
|
Handlebars.Exception,
|
||||||
|
'Unexpected node type "undefined" found when accepting path on MustacheStatement'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('arrays', function() {
|
describe('arrays', function() {
|
||||||
|
|||||||
+60
-11
@@ -21,8 +21,16 @@ describe('whitespace control', function() {
|
|||||||
shouldCompileTo(' {{~#if foo}} bar {{~/if}} ', hash, ' bar ');
|
shouldCompileTo(' {{~#if foo}} bar {{~/if}} ', hash, ' bar ');
|
||||||
shouldCompileTo(' {{#if foo}} bar {{/if}} ', hash, ' bar ');
|
shouldCompileTo(' {{#if foo}} bar {{/if}} ', hash, ' bar ');
|
||||||
|
|
||||||
shouldCompileTo(' \n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\n ', hash, 'bar');
|
shouldCompileTo(
|
||||||
shouldCompileTo(' a\n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\na ', hash, ' abara ');
|
' \n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\n ',
|
||||||
|
hash,
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
' a\n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\na ',
|
||||||
|
hash,
|
||||||
|
' abara '
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should strip whitespace around inverse block calls', function() {
|
it('should strip whitespace around inverse block calls', function() {
|
||||||
var hash = {};
|
var hash = {};
|
||||||
@@ -32,7 +40,11 @@ describe('whitespace control', function() {
|
|||||||
shouldCompileTo(' {{~^if foo}} bar {{~/if}} ', hash, ' bar ');
|
shouldCompileTo(' {{~^if foo}} bar {{~/if}} ', hash, ' bar ');
|
||||||
shouldCompileTo(' {{^if foo}} bar {{/if}} ', hash, ' bar ');
|
shouldCompileTo(' {{^if foo}} bar {{/if}} ', hash, ' bar ');
|
||||||
|
|
||||||
shouldCompileTo(' \n\n{{~^if foo~}} \n\nbar \n\n{{~/if~}}\n\n ', hash, 'bar');
|
shouldCompileTo(
|
||||||
|
' \n\n{{~^if foo~}} \n\nbar \n\n{{~/if~}}\n\n ',
|
||||||
|
hash,
|
||||||
|
'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<' };
|
||||||
@@ -44,8 +56,16 @@ describe('whitespace control', function() {
|
|||||||
|
|
||||||
shouldCompileTo('{{#if foo~}} bar {{~else~}} baz {{~/if}}', hash, 'bar');
|
shouldCompileTo('{{#if foo~}} bar {{~else~}} baz {{~/if}}', hash, 'bar');
|
||||||
|
|
||||||
shouldCompileTo('\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n', hash, 'bar');
|
shouldCompileTo(
|
||||||
shouldCompileTo('\n\n{{~#if foo~}} \n\n{{{foo}}} \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n', hash, 'bar<');
|
'\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n',
|
||||||
|
hash,
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
shouldCompileTo(
|
||||||
|
'\n\n{{~#if foo~}} \n\n{{{foo}}} \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n',
|
||||||
|
hash,
|
||||||
|
'bar<'
|
||||||
|
);
|
||||||
|
|
||||||
hash = {};
|
hash = {};
|
||||||
|
|
||||||
@@ -56,17 +76,46 @@ describe('whitespace control', function() {
|
|||||||
|
|
||||||
shouldCompileTo('{{#if foo~}} bar {{~else~}} baz {{~/if}}', hash, 'baz');
|
shouldCompileTo('{{#if foo~}} bar {{~else~}} baz {{~/if}}', hash, 'baz');
|
||||||
|
|
||||||
shouldCompileTo('\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n', hash, 'baz');
|
shouldCompileTo(
|
||||||
|
'\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n',
|
||||||
|
hash,
|
||||||
|
'baz'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should strip whitespace around partials', function() {
|
it('should strip whitespace around partials', function() {
|
||||||
shouldCompileToWithPartials('foo {{~> dude~}} ', [{}, {}, {dude: 'bar'}], true, 'foobar');
|
shouldCompileToWithPartials(
|
||||||
shouldCompileToWithPartials('foo {{> dude~}} ', [{}, {}, {dude: 'bar'}], true, 'foo bar');
|
'foo {{~> dude~}} ',
|
||||||
shouldCompileToWithPartials('foo {{> dude}} ', [{}, {}, {dude: 'bar'}], true, 'foo bar ');
|
[{}, {}, { dude: 'bar' }],
|
||||||
|
true,
|
||||||
|
'foobar'
|
||||||
|
);
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
'foo {{> dude~}} ',
|
||||||
|
[{}, {}, { dude: 'bar' }],
|
||||||
|
true,
|
||||||
|
'foo bar'
|
||||||
|
);
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
'foo {{> dude}} ',
|
||||||
|
[{}, {}, { dude: 'bar' }],
|
||||||
|
true,
|
||||||
|
'foo bar '
|
||||||
|
);
|
||||||
|
|
||||||
shouldCompileToWithPartials('foo\n {{~> dude}} ', [{}, {}, {dude: 'bar'}], true, 'foobar');
|
shouldCompileToWithPartials(
|
||||||
shouldCompileToWithPartials('foo\n {{> dude}} ', [{}, {}, {dude: 'bar'}], true, 'foo\n bar');
|
'foo\n {{~> dude}} ',
|
||||||
|
[{}, {}, { dude: 'bar' }],
|
||||||
|
true,
|
||||||
|
'foobar'
|
||||||
|
);
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
'foo\n {{> dude}} ',
|
||||||
|
[{}, {}, { dude: 'bar' }],
|
||||||
|
true,
|
||||||
|
'foo\n bar'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should only strip whitespace once', function() {
|
it('should only strip whitespace once', function() {
|
||||||
|
|||||||
+5
-2
@@ -8,7 +8,9 @@ module.exports = function(grunt) {
|
|||||||
execName = grunt.option('name'),
|
execName = grunt.option('name'),
|
||||||
events = {};
|
events = {};
|
||||||
|
|
||||||
async.each(_.keys(metrics), function(name, complete) {
|
async.each(
|
||||||
|
_.keys(metrics),
|
||||||
|
function(name, complete) {
|
||||||
if (/^_/.test(name) || (execName && name !== execName)) {
|
if (/^_/.test(name) || (execName && name !== execName)) {
|
||||||
return complete();
|
return complete();
|
||||||
}
|
}
|
||||||
@@ -18,6 +20,7 @@ module.exports = function(grunt) {
|
|||||||
complete();
|
complete();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
done);
|
done
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
+12
-2
@@ -10,7 +10,11 @@ module.exports = function(grunt) {
|
|||||||
cmd = 'node_modules\\.bin\\jison.cmd';
|
cmd = 'node_modules\\.bin\\jison.cmd';
|
||||||
}
|
}
|
||||||
|
|
||||||
var child = childProcess.spawn(cmd, ['-m', 'js', 'src/handlebars.yy', 'src/handlebars.l'], {stdio: 'inherit'});
|
var child = childProcess.spawn(
|
||||||
|
cmd,
|
||||||
|
['-m', 'js', 'src/handlebars.yy', 'src/handlebars.l'],
|
||||||
|
{ stdio: 'inherit' }
|
||||||
|
);
|
||||||
child.on('exit', function(code) {
|
child.on('exit', function(code) {
|
||||||
if (code != 0) {
|
if (code != 0) {
|
||||||
grunt.fatal('Jison failure: ' + code);
|
grunt.fatal('Jison failure: ' + code);
|
||||||
@@ -18,7 +22,13 @@ module.exports = function(grunt) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var src = ['src/parser-prefix.js', 'handlebars.js', 'src/parser-suffix.js'].map(grunt.file.read).join('');
|
var src = [
|
||||||
|
'src/parser-prefix.js',
|
||||||
|
'handlebars.js',
|
||||||
|
'src/parser-suffix.js'
|
||||||
|
]
|
||||||
|
.map(grunt.file.read)
|
||||||
|
.join('');
|
||||||
grunt.file.delete('handlebars.js');
|
grunt.file.delete('handlebars.js');
|
||||||
|
|
||||||
grunt.file.write('lib/handlebars/compiler/parser.js', src);
|
grunt.file.write('lib/handlebars/compiler/parser.js', src);
|
||||||
|
|||||||
+20
-5
@@ -66,8 +66,14 @@ module.exports = function(grunt) {
|
|||||||
var s3 = new AWS.S3(),
|
var s3 = new AWS.S3(),
|
||||||
bucket = process.env.S3_BUCKET_NAME;
|
bucket = process.env.S3_BUCKET_NAME;
|
||||||
|
|
||||||
async.each(_.keys(files), function(file, callback) {
|
async.each(
|
||||||
var params = {Bucket: bucket, Key: file, Body: grunt.file.read(files[file])};
|
_.keys(files),
|
||||||
|
function(file, callback) {
|
||||||
|
var params = {
|
||||||
|
Bucket: bucket,
|
||||||
|
Key: file,
|
||||||
|
Body: grunt.file.read(files[file])
|
||||||
|
};
|
||||||
s3.putObject(params, function(err) {
|
s3.putObject(params, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
@@ -77,15 +83,24 @@ module.exports = function(grunt) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
callback);
|
callback
|
||||||
|
);
|
||||||
}
|
}
|
||||||
function fileMap(suffixes) {
|
function fileMap(suffixes) {
|
||||||
var map = {};
|
var map = {};
|
||||||
_.each(['handlebars.js', 'handlebars.min.js', 'handlebars.runtime.js', 'handlebars.runtime.min.js'], function(file) {
|
_.each(
|
||||||
|
[
|
||||||
|
'handlebars.js',
|
||||||
|
'handlebars.min.js',
|
||||||
|
'handlebars.runtime.js',
|
||||||
|
'handlebars.runtime.min.js'
|
||||||
|
],
|
||||||
|
function(file) {
|
||||||
_.each(suffixes, function(suffix) {
|
_.each(suffixes, function(suffix) {
|
||||||
map[file.replace(/\.js$/, suffix + '.js')] = 'dist/' + file;
|
map[file.replace(/\.js$/, suffix + '.js')] = 'dist/' + file;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+36
-6
@@ -19,10 +19,19 @@ module.exports = function(grunt) {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
var expected = fs.readFileSync('./spec/expected/empty.amd.js').toString().replace(/\r\n/g, '\n');
|
var expected = fs
|
||||||
|
.readFileSync('./spec/expected/empty.amd.js')
|
||||||
|
.toString()
|
||||||
|
.replace(/\r\n/g, '\n');
|
||||||
|
|
||||||
if (stdout.toString() !== expected) {
|
if (stdout.toString() !== expected) {
|
||||||
throw new Error('Expected binary output differed:\n\n"' + stdout + '"\n\n"' + expected + '"');
|
throw new Error(
|
||||||
|
'Expected binary output differed:\n\n"' +
|
||||||
|
stdout +
|
||||||
|
'"\n\n"' +
|
||||||
|
expected +
|
||||||
|
'"'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
done();
|
done();
|
||||||
@@ -31,7 +40,9 @@ module.exports = function(grunt) {
|
|||||||
grunt.registerTask('test:mocha', function() {
|
grunt.registerTask('test:mocha', function() {
|
||||||
var done = this.async();
|
var done = this.async();
|
||||||
|
|
||||||
var runner = childProcess.fork('./spec/env/runner', [], {stdio: 'inherit'});
|
var runner = childProcess.fork('./spec/env/runner', [], {
|
||||||
|
stdio: 'inherit'
|
||||||
|
});
|
||||||
runner.on('close', function(code) {
|
runner.on('close', function(code) {
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
grunt.fatal(code + ' tests failed');
|
grunt.fatal(code + ' tests failed');
|
||||||
@@ -42,7 +53,11 @@ module.exports = function(grunt) {
|
|||||||
grunt.registerTask('test:cov', function() {
|
grunt.registerTask('test:cov', function() {
|
||||||
var done = this.async();
|
var done = this.async();
|
||||||
|
|
||||||
var runner = childProcess.fork('node_modules/istanbul/lib/cli.js', ['cover', '--source-map', '--', './spec/env/runner.js'], {stdio: 'inherit'});
|
var runner = childProcess.fork(
|
||||||
|
'node_modules/istanbul/lib/cli.js',
|
||||||
|
['cover', '--source-map', '--', './spec/env/runner.js'],
|
||||||
|
{ stdio: 'inherit' }
|
||||||
|
);
|
||||||
runner.on('close', function(code) {
|
runner.on('close', function(code) {
|
||||||
if (code != 0) {
|
if (code != 0) {
|
||||||
grunt.fatal(code + ' tests failed');
|
grunt.fatal(code + ' tests failed');
|
||||||
@@ -53,7 +68,9 @@ module.exports = function(grunt) {
|
|||||||
grunt.registerTask('test:min', function() {
|
grunt.registerTask('test:min', function() {
|
||||||
var done = this.async();
|
var done = this.async();
|
||||||
|
|
||||||
var runner = childProcess.fork('./spec/env/runner', ['--min'], {stdio: 'inherit'});
|
var runner = childProcess.fork('./spec/env/runner', ['--min'], {
|
||||||
|
stdio: 'inherit'
|
||||||
|
});
|
||||||
runner.on('close', function(code) {
|
runner.on('close', function(code) {
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
grunt.fatal(code + ' tests failed');
|
grunt.fatal(code + ' tests failed');
|
||||||
@@ -65,7 +82,20 @@ module.exports = function(grunt) {
|
|||||||
grunt.registerTask('test:check-cov', function() {
|
grunt.registerTask('test:check-cov', function() {
|
||||||
var done = this.async();
|
var done = this.async();
|
||||||
|
|
||||||
var runner = childProcess.fork('node_modules/istanbul/lib/cli.js', ['check-coverage', '--statements', '100', '--functions', '100', '--branches', '100', '--lines 100'], {stdio: 'inherit'});
|
var runner = childProcess.fork(
|
||||||
|
'node_modules/istanbul/lib/cli.js',
|
||||||
|
[
|
||||||
|
'check-coverage',
|
||||||
|
'--statements',
|
||||||
|
'100',
|
||||||
|
'--functions',
|
||||||
|
'100',
|
||||||
|
'--branches',
|
||||||
|
'100',
|
||||||
|
'--lines 100'
|
||||||
|
],
|
||||||
|
{ stdio: 'inherit' }
|
||||||
|
);
|
||||||
runner.on('close', function(code) {
|
runner.on('close', function(code) {
|
||||||
if (code != 0) {
|
if (code != 0) {
|
||||||
grunt.fatal('Coverage check failed: ' + code);
|
grunt.fatal('Coverage check failed: ' + code);
|
||||||
|
|||||||
+13
-5
@@ -17,7 +17,10 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
clean: function(callback) {
|
clean: function(callback) {
|
||||||
childProcess.exec('git diff-index --name-only HEAD --', {}, function(err, stdout) {
|
childProcess.exec('git diff-index --name-only HEAD --', {}, function(
|
||||||
|
err,
|
||||||
|
stdout
|
||||||
|
) {
|
||||||
callback(undefined, !err && !stdout);
|
callback(undefined, !err && !stdout);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -47,10 +50,13 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
master: function(callback) {
|
master: function(callback) {
|
||||||
childProcess.exec('git rev-parse --short origin/master', {}, function(err, stdout) {
|
childProcess.exec('git rev-parse --short origin/master', {}, function(
|
||||||
|
err,
|
||||||
|
stdout
|
||||||
|
) {
|
||||||
// This will error if master was not checked out but in this case we know we are not master
|
// This will error if master was not checked out but in this case we know we are not master
|
||||||
// so we can ignore.
|
// so we can ignore.
|
||||||
if (err && !(/Needed a single revision/.test(err.message))) {
|
if (err && !/Needed a single revision/.test(err.message)) {
|
||||||
throw new Error('git.master: ' + err.message);
|
throw new Error('git.master: ' + err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +83,9 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
tag: function(name, callback) {
|
tag: function(name, callback) {
|
||||||
childProcess.exec('git tag -a --message=' + name + ' ' + name, {}, function(err) {
|
childProcess.exec('git tag -a --message=' + name + ' ' + name, {}, function(
|
||||||
|
err
|
||||||
|
) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw new Error('git.tag: ' + err.message);
|
throw new Error('git.tag: ' + err.message);
|
||||||
}
|
}
|
||||||
@@ -98,7 +106,7 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var versionTags = tags.filter(function(info) {
|
var versionTags = tags.filter(function(info) {
|
||||||
return (/^v/.test(info[0]));
|
return /^v/.test(info[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
callback(undefined, versionTags[0] || tags[0]);
|
callback(undefined, versionTags[0] || tags[0]);
|
||||||
|
|||||||
+35
-9
@@ -3,13 +3,20 @@ var async = require('neo-async'),
|
|||||||
semver = require('semver');
|
semver = require('semver');
|
||||||
|
|
||||||
module.exports = function(grunt) {
|
module.exports = function(grunt) {
|
||||||
grunt.registerTask('version', 'Updates the current release version', function() {
|
grunt.registerTask(
|
||||||
|
'version',
|
||||||
|
'Updates the current release version',
|
||||||
|
function() {
|
||||||
var done = this.async(),
|
var done = this.async(),
|
||||||
pkg = grunt.config('pkg'),
|
pkg = grunt.config('pkg'),
|
||||||
version = grunt.option('ver');
|
version = grunt.option('ver');
|
||||||
|
|
||||||
if (!semver.valid(version)) {
|
if (!semver.valid(version)) {
|
||||||
throw new Error('Must provide a version number (Ex: --ver=1.0.0):\n\t' + version + '\n\n');
|
throw new Error(
|
||||||
|
'Must provide a version number (Ex: --ver=1.0.0):\n\t' +
|
||||||
|
version +
|
||||||
|
'\n\n'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg.version = version;
|
pkg.version = version;
|
||||||
@@ -17,11 +24,28 @@ module.exports = function(grunt) {
|
|||||||
|
|
||||||
grunt.log.writeln('Updating to version ' + version);
|
grunt.log.writeln('Updating to version ' + version);
|
||||||
|
|
||||||
async.each([
|
async.each(
|
||||||
['lib/handlebars/base.js', (/const VERSION = ['"](.*)['"];/), 'const VERSION = \'' + version + '\';'],
|
[
|
||||||
['components/bower.json', (/"version":.*/), '"version": "' + version + '",'],
|
[
|
||||||
['components/package.json', /"version":.*/, '"version": "' + version + '",'],
|
'lib/handlebars/base.js',
|
||||||
['components/handlebars.js.nuspec', (/<version>.*<\/version>/), '<version>' + version + '</version>']
|
/const VERSION = ['"](.*)['"];/,
|
||||||
|
"const VERSION = '" + version + "';"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'components/bower.json',
|
||||||
|
/"version":.*/,
|
||||||
|
'"version": "' + version + '",'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'components/package.json',
|
||||||
|
/"version":.*/,
|
||||||
|
'"version": "' + version + '",'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'components/handlebars.js.nuspec',
|
||||||
|
/<version>.*<\/version>/,
|
||||||
|
'<version>' + version + '</version>'
|
||||||
|
]
|
||||||
],
|
],
|
||||||
function(args, callback) {
|
function(args, callback) {
|
||||||
replace.apply(undefined, args);
|
replace.apply(undefined, args);
|
||||||
@@ -31,8 +55,10 @@ module.exports = function(grunt) {
|
|||||||
function() {
|
function() {
|
||||||
grunt.task.run(['default']);
|
grunt.task.run(['default']);
|
||||||
done();
|
done();
|
||||||
});
|
}
|
||||||
});
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function replace(path, regex, value) {
|
function replace(path, regex, value) {
|
||||||
var content = grunt.file.read(path);
|
var content = grunt.file.read(path);
|
||||||
|
|||||||
Reference in New Issue
Block a user