瀏覽代碼

Indent Partials

As referenced in this issue:
https://github.com/janl/mustache.js/issues/562

Partials aren't indented as per the spec:
https://github.com/mustache/spec/blob/master/specs/partials.yml#L13-L15

This adds indentation tracking for partials and applies them to the
first instance of a partial on a line (to not indent inline partials
which would violate a different part of the spec).
tags/v3.0.2
Kevin Dew Phillip Johnsen 9 年之前
父節點
當前提交
cadf571488
共有 3 個檔案被更改,包括 47 行新增11 行删除
  1. +40
    -6
      mustache.js
  2. +1
    -2
      test/mustache-spec-test.js
  3. +6
    -3
      test/parse-test.js

+ 40
- 6
mustache.js 查看文件

@@ -49,7 +49,7 @@
* Safe way of detecting whether or not the given thing is a primitive and * Safe way of detecting whether or not the given thing is a primitive and
* whether it has the given property * whether it has the given property
*/ */
function primitiveHasOwnProperty (primitive, propName) {
function primitiveHasOwnProperty (primitive, propName) {
return ( return (
primitive != null primitive != null
&& typeof primitive !== 'object' && typeof primitive !== 'object'
@@ -114,6 +114,10 @@
* Tokens that are the root node of a subtree contain two more elements: 1) an * Tokens that are the root node of a subtree contain two more elements: 1) an
* array of tokens in the subtree and 2) the index in the original template at * array of tokens in the subtree and 2) the index in the original template at
* which the closing tag for that section begins. * which the closing tag for that section begins.
*
* Tokens for partials also contain two more elements: 1) a string value of
* indendation prior to that tag and 2) the index of that tag on that line -
* eg a value of 2 indicates the partial is the third tag on this line.
*/ */
function parseTemplate (template, tags) { function parseTemplate (template, tags) {
if (!template) if (!template)
@@ -124,6 +128,8 @@
var spaces = []; // Indices of whitespace tokens on the current line var spaces = []; // Indices of whitespace tokens on the current line
var hasTag = false; // Is there a {{tag}} on the current line? var hasTag = false; // Is there a {{tag}} on the current line?
var nonSpace = false; // Is there a non-space char on the current line? var nonSpace = false; // Is there a non-space char on the current line?
var indentation = ''; // Tracks indentation for tags that use it
var tagIndex = 0; // Stores a count of number of tags encountered on a line


// Strips all whitespace tokens array for the current line // Strips all whitespace tokens array for the current line
// if there was a {{#tag}} on it and otherwise only space. // if there was a {{#tag}} on it and otherwise only space.
@@ -169,6 +175,8 @@


if (isWhitespace(chr)) { if (isWhitespace(chr)) {
spaces.push(tokens.length); spaces.push(tokens.length);
if (!nonSpace)
indentation += chr;
} else { } else {
nonSpace = true; nonSpace = true;
} }
@@ -177,8 +185,11 @@
start += 1; start += 1;


// Check for whitespace on the current line. // Check for whitespace on the current line.
if (chr === '\n')
if (chr === '\n') {
stripSpace(); stripSpace();
indentation = '';
tagIndex = 0;
}
} }
} }


@@ -210,7 +221,12 @@
if (!scanner.scan(closingTagRe)) if (!scanner.scan(closingTagRe))
throw new Error('Unclosed tag at ' + scanner.pos); throw new Error('Unclosed tag at ' + scanner.pos);


token = [ type, value, start, scanner.pos ];
if (type == '>') {
token = [ type, value, start, scanner.pos, indentation, tagIndex ];
} else {
token = [ type, value, start, scanner.pos ];
}
tagIndex++;
tokens.push(token); tokens.push(token);


if (type === '#' || type === '^') { if (type === '#' || type === '^') {
@@ -418,7 +434,7 @@
while (intermediateValue != null && index < names.length) { while (intermediateValue != null && index < names.length) {
if (index === names.length - 1) if (index === names.length - 1)
lookupHit = ( lookupHit = (
hasProperty(intermediateValue, names[index])
hasProperty(intermediateValue, names[index])
|| primitiveHasOwnProperty(intermediateValue, names[index]) || primitiveHasOwnProperty(intermediateValue, names[index])
); );


@@ -592,12 +608,30 @@
return this.renderTokens(token[4], context, partials, originalTemplate); return this.renderTokens(token[4], context, partials, originalTemplate);
}; };


Writer.prototype.indentPartial = function indentPartial (partial, indentation) {
var filteredIndentation = indentation.replace(/[^ \t]/g, '');
var partialByNl = partial.split('\n');
for (var i = 0; i < partialByNl.length; i++) {
if (partialByNl[i].length) {
partialByNl[i] = filteredIndentation + partialByNl[i];
}
}
return partialByNl.join('\n');
};

Writer.prototype.renderPartial = function renderPartial (token, context, partials, tags) { Writer.prototype.renderPartial = function renderPartial (token, context, partials, tags) {
if (!partials) return; if (!partials) return;


var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
if (value != null)
return this.renderTokens(this.parse(value, tags), context, partials, value);
if (value != null) {
var tagIndex = token[5];
var indentation = token[4];
var indentedValue = value;
if (tagIndex == 0 && indentation) {
indentedValue = this.indentPartial(value, indentation);
}
return this.renderTokens(this.parse(indentedValue, tags), context, partials, value);
}
}; };


Writer.prototype.unescapedValue = function unescapedValue (token, context) { Writer.prototype.unescapedValue = function unescapedValue (token, context) {


+ 1
- 2
test/mustache-spec-test.js 查看文件

@@ -16,8 +16,7 @@ var skipTests = {
], ],
partials: [ partials: [
'Standalone Without Previous Line', 'Standalone Without Previous Line',
'Standalone Without Newline',
'Standalone Indentation'
'Standalone Without Newline'
], ],
sections: [ sections: [
'Standalone Without Newline' 'Standalone Without Newline'


+ 6
- 3
test/parse-test.js 查看文件

@@ -40,9 +40,12 @@ var expectations = {
'a\n{{#a}}\n{{#b}}\n{{/b}}\n{{/a}}\nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 2, 8, [ [ '#', 'b', 9, 15, [], 16 ] ], 23 ], [ 'text', 'b', 30, 31 ] ], 'a\n{{#a}}\n{{#b}}\n{{/b}}\n{{/a}}\nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 2, 8, [ [ '#', 'b', 9, 15, [], 16 ] ], 23 ], [ 'text', 'b', 30, 31 ] ],
'a\n {{#a}}\n{{#b}}\n{{/b}}\n{{/a}}\nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 3, 9, [ [ '#', 'b', 10, 16, [], 17 ] ], 24 ], [ 'text', 'b', 31, 32 ] ], 'a\n {{#a}}\n{{#b}}\n{{/b}}\n{{/a}}\nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 3, 9, [ [ '#', 'b', 10, 16, [], 17 ] ], 24 ], [ 'text', 'b', 31, 32 ] ],
'a\n {{#a}}\n{{#b}}\n{{/b}}\n{{/a}} \nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 3, 9, [ [ '#', 'b', 10, 16, [], 17 ] ], 24 ], [ 'text', 'b', 32, 33 ] ], 'a\n {{#a}}\n{{#b}}\n{{/b}}\n{{/a}} \nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 3, 9, [ [ '#', 'b', 10, 16, [], 17 ] ], 24 ], [ 'text', 'b', 32, 33 ] ],
'{{>abc}}' : [ [ '>', 'abc', 0, 8 ] ],
'{{> abc }}' : [ [ '>', 'abc', 0, 10 ] ],
'{{ > abc }}' : [ [ '>', 'abc', 0, 11 ] ],
'{{>abc}}' : [ [ '>', 'abc', 0, 8, '', 0 ] ],
'{{> abc }}' : [ [ '>', 'abc', 0, 10, '', 0 ] ],
'{{ > abc }}' : [ [ '>', 'abc', 0, 11, '', 0 ] ],
' {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0 ] ],
' {{> abc }} {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0 ], [ '>', 'abc', 13, 23, ' ', 1 ] ],
'{{ > abc }}' : [ [ '>', 'abc', 0, 11, '', 0 ] ],
'{{=<% %>=}}' : [ [ '=', '<% %>', 0, 11 ] ], '{{=<% %>=}}' : [ [ '=', '<% %>', 0, 11 ] ],
'{{= <% %> =}}' : [ [ '=', '<% %>', 0, 13 ] ], '{{= <% %> =}}' : [ [ '=', '<% %>', 0, 13 ] ],
'{{=<% %>=}}<%={{ }}=%>' : [ [ '=', '<% %>', 0, 11 ], [ '=', '{{ }}', 11, 22 ] ], '{{=<% %>=}}<%={{ }}=%>' : [ [ '=', '<% %>', 0, 11 ], [ '=', '{{ }}', 11, 22 ] ],


Loading…
取消
儲存