Skip to content

Commit

Permalink
tree: proper nesting
Browse files Browse the repository at this point in the history
  • Loading branch information
indutny committed Apr 27, 2015
1 parent 5ce73b1 commit 321b135
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 45 deletions.
82 changes: 48 additions & 34 deletions lib/bemhtml/runtime/tree.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,53 @@
var inherits = require('inherits');

function Template(predicates, body) {
this.predicates = predicates;
this.body = body;
}
exports.Template = Template;

function Item(tree, args) {
this.args = args;
this.children = [];

for (var i = args.length - 1; i >= 0; i--) {
var arg = args[i];
if (arg !== tree.boundBody)
continue;

args[i] = tree.queue.pop();
}
function MatchBase() {
}
exports.MatchBase = MatchBase;

for (var i = 0; i < args.length; i++) {
if (!(args[i] instanceof Item))
continue;
function Item(tree, children) {
this.conditions = [];
this.children = [];

var arg = args[i];
args.splice(i, 1);
i--;
this.children.push(arg);
for (var i = children.length - 1; i >= 0; i--) {
var arg = children[i];
if (arg instanceof MatchBase)
this.conditions.push(arg);
else if (arg === tree.boundBody)
this.children[i] = tree.queue.pop();
else
this.children[i] = arg;
}
}

function PropertyMatch(key, value) {
MatchBase.call(this);

this.key = key;
this.value = value;
}
inherits(PropertyMatch, MatchBase);
exports.PropertyMatch = PropertyMatch;

function PropertyAbsent(key) {
MatchBase.call(this);

this.key = key;
}
inherits(PropertyAbsent, MatchBase);
exports.PropertyAbsent = PropertyAbsent;

function CustomMatch(body) {
MatchBase.call(this);

this.body = body;
}
inherits(CustomMatch, MatchBase);
exports.CustomMatch = CustomMatch;

function Tree(options) {
Expand Down Expand Up @@ -85,19 +92,19 @@ Tree.prototype.methods = function methods(kind) {
var boundBody = this.boundBody;

if (kind !== 'body') {
return function() {
return function wrapNotBody() {
method.apply(self, arguments);
return boundBody;
};
}

return function() {
return function wrapBody() {
var res = method.apply(self, arguments);

// Insert body into last item
var child = self.queue.pop();
var last = self.queue[self.queue.length - 1];
last.args = last.args.concat(child.args);
last.conditions = last.conditions.concat(child.conditions);
last.children = last.children.concat(child.children);

if (name === 'replace' || name === 'extend')
Expand All @@ -109,25 +116,32 @@ Tree.prototype.methods = function methods(kind) {

// Called after all matches
Tree.prototype.flush = function flush(conditions, item) {
if (item.children.length > 0) {
// Sub-template
var subcond = conditions.concat(item.args);
var subcond;

// Reverse order
for (var i = 0; i < item.children.length; i++)
if (item.conditions)
subcond = conditions.concat(item.conditions);
else
subcond = item.conditions;

for (var i = 0; i < item.children.length; i++) {
var arg = item.children[i];

// Go deeper
if (arg instanceof Item)
this.flush(subcond, item.children[i]);
} else {

// Body
this.templates.push(new Template(conditions, item.args[0]));
else
this.templates.push(new Template(conditions, arg));
}
};

Tree.prototype.body = function body() {
var args = new Array(arguments.length);
var children = new Array(arguments.length);
for (var i = 0; i < arguments.length; i++)
args[i] = arguments[i];
children[i] = arguments[i];

var child = new Item(this, args);
var child = new Item(this, children);
this.queue[this.queue.length - 1].children.push(child);

if (this.queue.length === 1)
Expand All @@ -137,15 +151,15 @@ Tree.prototype.body = function body() {
};

Tree.prototype.match = function match() {
var args = new Array(arguments.length);
var children = new Array(arguments.length);
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (typeof arg === 'function')
arg = new CustomMatch(arg);
args[i] = arg;
children[i] = arg;
}

this.queue.push(new Item(this, args));
this.queue.push(new Item(this, children));

return this.boundBody;
};
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"license": "MIT",
"dependencies": {
"coa": "~0.3.9",
"inherits": "^2.0.1",
"q": "~0.9.3"
},
"devDependencies": {
Expand Down
24 changes: 13 additions & 11 deletions test/runtime-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,19 @@ describe('BEMHTML compiler/Runtime', function() {
});

describe('position in Context', function() {
test(function() {
block('b1').content()(function() { return this.position; });
}, [
{ block: 'b1' },
{ block: 'b1' },
{ block: 'b1' },
{ block: 'b1' }
], '<div class="b1">1</div>' +
'<div class="b1">2</div>' +
'<div class="b1">3</div>' +
'<div class="b1">4</div>');
it('should have proper this.position', function() {
test(function() {
block('b1').content()(function() { return this.position; });
}, [
{ block: 'b1' },
{ block: 'b1' },
{ block: 'b1' },
{ block: 'b1' }
], '<div class="b1">1</div>' +
'<div class="b1">2</div>' +
'<div class="b1">3</div>' +
'<div class="b1">4</div>');
});
});

describe('attrs in BEMJSON', function() {
Expand Down
13 changes: 13 additions & 0 deletions test/tree-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,17 @@ describe('BEMHTML compiler/Tree', function() {
});
}, {}, 'ok');
});

it('should support mixed direct/nested bodies', function() {
test(function() {
block('page')(
content()(
function() { return 'ok'; },
match(function() { return true; })(function() {
return applyNext();
})
)
);
}, { block: 'page' }, '<div class="page">ok</div>');
});
});

0 comments on commit 321b135

Please sign in to comment.