Skip to content

Commit

Permalink
runtime: skip flushing on overridden .def()
Browse files Browse the repository at this point in the history
Fix: #40
  • Loading branch information
indutny committed Jul 23, 2015
1 parent 46860e9 commit 678e33e
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 17 deletions.
21 changes: 20 additions & 1 deletion bench/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ var benchmark = require('benchmark');
var argv = require('yargs')
.describe('grep', 'filter templates to run')
.describe('compare', 'compare with the previous bem-xjst version')
.describe('compile', 'compare compile time too')
.describe('compile', 'benchmark compile')
.describe('flush', 'benchmark _flush()')
.describe('min-samples', 'minimum number of samples')
.describe('max-time', 'maximum amount of time to wait')
.help('h')
Expand Down Expand Up @@ -88,6 +89,24 @@ templates.forEach(function(template) {
precompiled.apply(input);
});
});

if (argv.flush) {
both(function(version, xjst) {
var precompiled = xjst.compile(template.content, {
context: 'this'
});
var input = JSON.parse(template.input);

precompiled.BEMContext.prototype._flush = function _flush(str) {
return '';
};

// Rendering speed
suite.add('flush:' + template.name + ':' + version, function() {
precompiled.apply(input);
});
});
}
});

suite.on('cycle', function(event) {
Expand Down
4 changes: 4 additions & 0 deletions lib/bemhtml/runtime/entity.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ function Entity(bemhtml, block, elem, templates) {
this.elem = null;
this.jsClass = null;

// `true` if entity has just a default renderer for `def()` mode
this.defaultRenderer = true;

// "Fast modes"
this.def = new Match(this);
this.tag = new Match(this);
Expand Down Expand Up @@ -100,6 +103,7 @@ Entity.prototype.setDefaults = function setDefaults() {

// .def() default
if (this.def.count !== 0) {
this.defaultRenderer = false;
var self = this;
this.def.push(new Template([], function defaultBodyProxy() {
return self.defaultBody(this);
Expand Down
31 changes: 25 additions & 6 deletions lib/bemhtml/runtime/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ function BEMHTML() {
// Execution depth, used to invalidate `applyNext` bitfields
this.depth = 0;

// Do not call `_flush` on overridden `def()` mode
this.canFlush = false;

// oninit templates
this.oninit = null;

Expand Down Expand Up @@ -184,6 +187,7 @@ BEMHTML.prototype.run = function run(json) {

this.match = null;
this.context = new this.contextConstructor(this);
this.canFlush = this.context._flush !== null;
this.depth = 0;
var res = this._run(json);

Expand Down Expand Up @@ -213,8 +217,13 @@ BEMHTML.prototype.runMany = function runMany(arr) {
}
context._notNewList = true;

for (var i = 0; i < arr.length; i++)
out += this._run(arr[i]);
if (this.canFlush) {
for (var i = 0; i < arr.length; i++)
out += context._flush(this._run(arr[i]));
} else {
for (var i = 0; i < arr.length; i++)
out += this._run(arr[i]);
}

if (!prevNotNewList)
context.position = prevPos;
Expand Down Expand Up @@ -279,8 +288,16 @@ BEMHTML.prototype.runOne = function runOne(json) {
else
key = block + '__' + elem;

var restoreFlush = false;
var ent = this.entities[key];
if (!ent) {
if (ent) {
if (this.canFlush && !ent.defaultRenderer) {
// Entity does not support flushing, do not flush anything nested
restoreFlush = true;
this.canFlush = false;
}
} else {
// No entity - use default one
ent = this.defaultEnt;
ent.init(block, elem);
}
Expand All @@ -292,6 +309,8 @@ BEMHTML.prototype.runOne = function runOne(json) {
context.mods = oldMods;
context.elemMods = oldElemMods;
this.depth--;
if (restoreFlush)
this.canFlush = true;

return res;
};
Expand Down Expand Up @@ -424,11 +443,11 @@ BEMHTML.prototype.renderClose = function renderClose(prefix,

if (utils.isShortTag(tag)) {
out += '/>';
if (context._flush !== null)
if (this.canFlush)
out = context._flush(out);
} else {
out += '>';
if (context._flush !== null)
if (this.canFlush)
out = context._flush(out);

// TODO(indutny): skip apply next flags
Expand All @@ -438,7 +457,7 @@ BEMHTML.prototype.renderClose = function renderClose(prefix,
out += '</' + tag + '>';
}

if (context._flush !== null)
if (this.canFlush)
out = context._flush(out);
return out;
};
Expand Down
18 changes: 8 additions & 10 deletions test/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,21 @@ function test(fn, data, expected, options) {
if (!options) options = {};

var body = fn2str(fn);
var fns = [
bemxjst.compile(body, options)
];
var template = bemxjst.compile(body, options)

// Invoke multiple times
if (options.count !== undefined)
for (var i = 1; i < options.count; i++)
fns.push(fns[0]);

fns.forEach(function(fn, i) {
var count = options.count || 1;
for (var i = 0; i < count; i++) {
try {
assert.equal(fn.apply.call(data || {}), expected, i);
assert.equal(template.apply.call(data || {}), expected, i);
} catch (e) {
console.error(e.stack);
throw e;
}
});
}

if (options.after)
options.after(template);
}
exports.test = test;

Expand Down
41 changes: 41 additions & 0 deletions test/runtime-test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var assert = require('assert');
var fixtures = require('./fixtures');

var test = fixtures.test;
Expand Down Expand Up @@ -391,6 +392,46 @@ describe('BEMHTML compiler/Runtime', function() {
}
}, '[3.[0.<div class="b1">][2.[1.<div class="b2">]</div>]</div>]');
});

it('should not flush custom def() bodies', function () {
test(function() {
oninit(function(exports) {
exports._buf = [];
exports.BEMContext.prototype._flush = function flush(str) {
if (str !== '')
exports._buf.push(str);
return '';
};
});

block('b2').def()(function() {
return 'before' + applyNext() + 'after';
});

block('*').tag()('a');
}, {
block: 'b1',
content: [ {
block: 'b2',
content: {
block: 'b3'
}
}, {
block: 'b4',
content: 'ending'
} ]
}, '', {
after: function after(template) {
assert.deepEqual(template._buf, [
'<a class="b1">',
'before<a class="b2"><a class="b3"></a></a>after',
'<a class="b4">',
'ending</a>',
'</a>'
]);
}
});
});
});

describe('attrs in BEMJSON', function() {
Expand Down

0 comments on commit 678e33e

Please sign in to comment.