Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ee913e28bd | |||
| 7a77f61c44 | |||
| 72753bcaa3 | |||
| f3d266a66e | |||
| a023cb4dd9 | |||
| c7dc353956 |
@@ -31,7 +31,10 @@ function Exception(message, node) {
|
|||||||
// Work around issue under safari where we can't directly set the column value
|
// Work around issue under safari where we can't directly set the column value
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
if (Object.defineProperty) {
|
if (Object.defineProperty) {
|
||||||
Object.defineProperty(this, 'column', {value: column});
|
Object.defineProperty(this, 'column', {
|
||||||
|
value: column,
|
||||||
|
enumerable: true
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.column = column;
|
this.column = column;
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-10
@@ -210,12 +210,7 @@ export function wrapProgram(container, i, fn, data, declaredBlockParams, blockPa
|
|||||||
export function resolvePartial(partial, context, options) {
|
export function resolvePartial(partial, context, options) {
|
||||||
if (!partial) {
|
if (!partial) {
|
||||||
if (options.name === '@partial-block') {
|
if (options.name === '@partial-block') {
|
||||||
let data = options.data;
|
partial = options.data['partial-block'];
|
||||||
while (data['partial-block'] === noop) {
|
|
||||||
data = data._parent;
|
|
||||||
}
|
|
||||||
partial = data['partial-block'];
|
|
||||||
data['partial-block'] = noop;
|
|
||||||
} else {
|
} else {
|
||||||
partial = options.partials[options.name];
|
partial = options.partials[options.name];
|
||||||
}
|
}
|
||||||
@@ -228,6 +223,8 @@ export function resolvePartial(partial, context, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function invokePartial(partial, context, options) {
|
export function invokePartial(partial, context, options) {
|
||||||
|
// Use the current closure context to save the partial-block if this partial
|
||||||
|
const currentPartialBlock = options.data && options.data['partial-block'];
|
||||||
options.partial = true;
|
options.partial = true;
|
||||||
if (options.ids) {
|
if (options.ids) {
|
||||||
options.data.contextPath = options.ids[0] || options.data.contextPath;
|
options.data.contextPath = options.ids[0] || options.data.contextPath;
|
||||||
@@ -236,10 +233,17 @@ export function invokePartial(partial, context, options) {
|
|||||||
let partialBlock;
|
let partialBlock;
|
||||||
if (options.fn && options.fn !== noop) {
|
if (options.fn && options.fn !== noop) {
|
||||||
options.data = createFrame(options.data);
|
options.data = createFrame(options.data);
|
||||||
partialBlock = options.data['partial-block'] = options.fn;
|
// Wrapper function to get access to currentPartialBlock from the closure
|
||||||
|
let fn = options.fn;
|
||||||
if (partialBlock.partials) {
|
partialBlock = options.data['partial-block'] = function partialBlockWrapper(context, options) {
|
||||||
options.partials = Utils.extend({}, options.partials, partialBlock.partials);
|
// Restore the partial-block from the closure for the execution of the block
|
||||||
|
// i.e. the part inside the block of the partial call.
|
||||||
|
options.data = createFrame(options.data);
|
||||||
|
options.data['partial-block'] = currentPartialBlock;
|
||||||
|
return fn(context, options);
|
||||||
|
};
|
||||||
|
if (fn.partials) {
|
||||||
|
options.partials = Utils.extend({}, options.partials, fn.partials);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,31 @@ describe('compiler', function() {
|
|||||||
}, 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() {
|
||||||
|
try {
|
||||||
|
Handlebars.compile(' \n {{#if}}\n{{/def}}')();
|
||||||
|
equal(true, false, 'Statement must throw exception. This line should not be executed.');
|
||||||
|
} catch (err) {
|
||||||
|
equal(err.message, 'if doesn\'t match def - 2:5', 'Checking error message');
|
||||||
|
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,
|
||||||
|
// its value won't change (https://github.com/jquery/esprima/issues/1290#issuecomment-132455482)
|
||||||
|
// Since this was neither working in Handlebars 3 nor in 4.0.5, we only check the column for other browsers.
|
||||||
|
equal(err.column, 5, 'Checking error column');
|
||||||
|
}
|
||||||
|
equal(err.lineNumber, 2, 'Checking error row');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should include the location as enumerable property', function() {
|
||||||
|
try {
|
||||||
|
Handlebars.compile(' \n {{#if}}\n{{/def}}')();
|
||||||
|
equal(true, false, 'Statement must throw exception. This line should not be executed.');
|
||||||
|
} catch (err) {
|
||||||
|
equal(err.propertyIsEnumerable('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',
|
||||||
|
|||||||
@@ -249,6 +249,13 @@ describe('partials', function() {
|
|||||||
true,
|
true,
|
||||||
'success');
|
'success');
|
||||||
});
|
});
|
||||||
|
it('should be able to render the partial-block twice', function() {
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
'{{#> dude}}success{{/dude}}',
|
||||||
|
[{}, {}, {dude: '{{> @partial-block }} {{> @partial-block }}'}],
|
||||||
|
true,
|
||||||
|
'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}}',
|
||||||
@@ -256,6 +263,32 @@ describe('partials', function() {
|
|||||||
true,
|
true,
|
||||||
'success');
|
'success');
|
||||||
});
|
});
|
||||||
|
it('should allow the #each-helper to be used along with partial-blocks', function() {
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
'<template>{{#> list value}}value = {{.}}{{/list}}</template>',
|
||||||
|
[
|
||||||
|
{value: ['a', 'b', 'c']},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
list: '<list>{{#each .}}<item>{{> @partial-block}}</item>{{/each}}</list>'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
'<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() {
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
'{{#> dude}}{{value}}{{/dude}}',
|
||||||
|
[
|
||||||
|
{context: {value: 'success'}},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
dude: '{{#with context}}{{> @partial-block }} {{> @partial-block }}{{/with}}'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
'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}}',
|
||||||
@@ -284,6 +317,50 @@ describe('partials', function() {
|
|||||||
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() {
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
'<template>{{#> outer}}{{value}}{{/outer}}</template>',
|
||||||
|
[
|
||||||
|
{value: 'success'},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
outer: '<outer>{{#> nested}}<outer-block>{{> @partial-block}}</outer-block>{{/nested}}{{> @partial-block}}</outer>',
|
||||||
|
nested: '<nested>{{> @partial-block}}</nested>'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
'<template><outer><nested><outer-block>success</outer-block></nested>success</outer></template>');
|
||||||
|
});
|
||||||
|
it('should render nested partial blocks at different nesting levels (twice)', function() {
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
'<template>{{#> outer}}{{value}}{{/outer}}</template>',
|
||||||
|
[
|
||||||
|
{value: 'success'},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
outer: '<outer>{{#> nested}}<outer-block>{{> @partial-block}} {{> @partial-block}}</outer-block>{{/nested}}{{> @partial-block}}+{{> @partial-block}}</outer>',
|
||||||
|
nested: '<nested>{{> @partial-block}}</nested>'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
'<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() {
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
'<template>{{#> outer}}{{value}}{{/outer}}</template>',
|
||||||
|
[
|
||||||
|
{value: 'success'},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
outer: '<outer>{{#> nested}}<outer-block>{{> @partial-block}} {{> @partial-block}}</outer-block>{{/nested}}</outer>',
|
||||||
|
nested: '<nested>{{> @partial-block}}{{> @partial-block}}</nested>'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
'<template><outer>' +
|
||||||
|
'<nested><outer-block>success success</outer-block><outer-block>success success</outer-block></nested>' +
|
||||||
|
'</outer></template>');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('inline partials', function() {
|
describe('inline partials', function() {
|
||||||
@@ -332,6 +409,24 @@ describe('partials', function() {
|
|||||||
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() {
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
'{{#*inline "outer"}}{{#>inner}}<outer-block>{{>@partial-block}}</outer-block>{{/inner}}{{>@partial-block}}{{/inline}}' +
|
||||||
|
'{{#*inline "inner"}}<inner>{{>@partial-block}}</inner>{{/inline}}' +
|
||||||
|
'{{#>outer}}{{value}}{{/outer}}',
|
||||||
|
[{value: 'success'}, {}, {}],
|
||||||
|
true,
|
||||||
|
'<inner><outer-block>success</outer-block></inner>success');
|
||||||
|
});
|
||||||
|
it('should render nested inline partials (twice at each level)', function() {
|
||||||
|
shouldCompileToWithPartials(
|
||||||
|
'{{#*inline "outer"}}{{#>inner}}<outer-block>{{>@partial-block}} {{>@partial-block}}</outer-block>{{/inner}}{{/inline}}' +
|
||||||
|
'{{#*inline "inner"}}<inner>{{>@partial-block}}{{>@partial-block}}</inner>{{/inline}}' +
|
||||||
|
'{{#>outer}}{{value}}{{/outer}}',
|
||||||
|
[{value: 'success'}, {}, {}],
|
||||||
|
true,
|
||||||
|
'<inner><outer-block>success success</outer-block><outer-block>success success</outer-block></inner>');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pass compiler flags', function() {
|
it('should pass compiler flags', function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user