mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
complete Spacebars code gen
This commit is contained in:
@@ -427,14 +427,16 @@ Spacebars.parse = function (inputString) {
|
||||
while (stacheTags[i] !== b.closeTag)
|
||||
i++;
|
||||
} else if (t.type === 'BLOCKCLOSE') {
|
||||
var name = t.path.join('.');
|
||||
if (isTopLevel)
|
||||
throw new Error("Unexpected close tag `" +t.name + "` at " +
|
||||
throw new Error("Unexpected close tag `" + name + "` at " +
|
||||
prettyOffset(inputString, t.charPos));
|
||||
if (t.name !== block.openTag.name)
|
||||
if (name !== block.openTag.path.join('.'))
|
||||
throw new Error("Close tag at " +
|
||||
prettyOffset(inputString, t.charPos) +
|
||||
" doesn't match `" + block.openTag.name +
|
||||
"`, found `" + t.name + "`");
|
||||
" doesn't match `" +
|
||||
block.openTag.path.join('.') +
|
||||
"`, found `" + name + "`");
|
||||
block.closeTag = t;
|
||||
} else if (t.type === 'ELSE') {
|
||||
if (isTopLevel)
|
||||
@@ -574,11 +576,19 @@ Spacebars.compile = function (inputString) {
|
||||
};
|
||||
|
||||
// returns: array of source strings, or null if no
|
||||
// args at all
|
||||
var codeGenArgs = function (tagArgs, funcInfo, forComponent) {
|
||||
// args at all.
|
||||
// if forComponentWithOpts is truthy, perform
|
||||
// component invocation argument handling.
|
||||
// forComponentWithOpts is a map from name of keyword
|
||||
// argument to source code. For example,
|
||||
// `{ bodyClass: "Component.extend(..." }`.
|
||||
var codeGenArgs = function (tagArgs, funcInfo,
|
||||
forComponentWithOpts) {
|
||||
var options = null; // source -> source
|
||||
var args = null; // [source]
|
||||
|
||||
var forComponent = !! forComponentWithOpts;
|
||||
|
||||
_.each(tagArgs, function (arg, i) {
|
||||
var argType = arg[0];
|
||||
var argValue = arg[1];
|
||||
@@ -602,7 +612,10 @@ Spacebars.compile = function (inputString) {
|
||||
if (arg.length > 2) {
|
||||
// keyword argument
|
||||
options = (options || {});
|
||||
options[toJSLiteral(arg[2])] = argCode;
|
||||
if (! (forComponentWithOpts &&
|
||||
(arg[2] in forComponentWithOpts))) {
|
||||
options[toJSLiteral(arg[2])] = argCode;
|
||||
}
|
||||
} else {
|
||||
// positional argument
|
||||
if (forComponent) {
|
||||
@@ -620,6 +633,11 @@ Spacebars.compile = function (inputString) {
|
||||
});
|
||||
|
||||
if (forComponent) {
|
||||
_.each(forComponentWithOpts, function (v, k) {
|
||||
options = (options || {});
|
||||
options[toJSLiteral(k)] = v;
|
||||
});
|
||||
|
||||
// components get one argument, the options dictionary
|
||||
args = [options ? makeObjectLiteral(options) : '{}'];
|
||||
} else {
|
||||
@@ -709,15 +727,33 @@ Spacebars.compile = function (inputString) {
|
||||
// tag or block
|
||||
var tag = tagOrStr;
|
||||
if (tag.isBlock) {
|
||||
// XXX implement
|
||||
var block = tag;
|
||||
var nameCode = codeGenPath(
|
||||
block.openTag.path, funcInfo);
|
||||
var extraArgs = {
|
||||
bodyClass: 'Component.extend({render: ' +
|
||||
tokensToRenderFunc(block.bodyTokens, indent) +
|
||||
'})'
|
||||
};
|
||||
if (block.elseTokens) {
|
||||
extraArgs.elseClass =
|
||||
'Component.extend({render: ' +
|
||||
tokensToRenderFunc(block.elseTokens, indent) +
|
||||
'})';
|
||||
}
|
||||
var argCode =
|
||||
codeGenArgs(block.openTag.args, funcInfo,
|
||||
extraArgs)[0];
|
||||
bodyLines.push('buf.component(function () { return ((' + nameCode + ') || EmptyComponent).create(' + argCode +
|
||||
'); });');
|
||||
} else {
|
||||
switch (tag.type) {
|
||||
case 'INCLUSION':
|
||||
var nameCode = codeGenPath(tag.path, funcInfo);
|
||||
var argCode =
|
||||
codeGenArgs(tag.args, funcInfo, true);
|
||||
bodyLines.push('buf.component(function () { return ((' + nameCode + ') || EmptyComponent).create(' +
|
||||
(argCode ? argCode.join(', ') : '') + '); });');
|
||||
codeGenArgs(tag.args, funcInfo, {})[0];
|
||||
bodyLines.push('buf.component(function () { return ((' + nameCode + ') || EmptyComponent).create(' + argCode +
|
||||
'); });');
|
||||
break;
|
||||
case 'DOUBLE':
|
||||
case 'TRIPLE':
|
||||
@@ -802,8 +838,8 @@ Spacebars.compile = function (inputString) {
|
||||
(bodyLines ?
|
||||
(funcInfo.usedSelf ?
|
||||
'\n' + indent + 'var self = this;' : '') +
|
||||
'\n' + indent + bodyLines.join('\n' + indent) + '\n' :
|
||||
'') + '}';
|
||||
'\n' + indent + bodyLines.join('\n' + indent) + '\n' +
|
||||
oldIndent : '') + '}';
|
||||
};
|
||||
|
||||
return tokensToRenderFunc(tree.bodyTokens);
|
||||
|
||||
@@ -326,8 +326,24 @@ Tinytest.add("spacebars - compiler", function (test) {
|
||||
var run = function (input/*, expectedLines*/) {
|
||||
var expectedLines = Array.prototype.slice.call(arguments, 1);
|
||||
var expected = expectedLines.join('\n');
|
||||
var output = Spacebars.compile(input);
|
||||
test.equal(output, expected);
|
||||
if (arguments[1].fail) {
|
||||
var expectedMessage = arguments[1].fail;
|
||||
// test for error starting with expectedMessage
|
||||
var msg = '';
|
||||
test.throws(function () {
|
||||
try {
|
||||
Spacebars.compile(input);
|
||||
} catch (e) {
|
||||
msg = e.message;
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
test.equal(msg.slice(0, expectedMessage.length),
|
||||
expectedMessage);
|
||||
} else {
|
||||
var output = Spacebars.compile(input);
|
||||
test.equal(output, expected);
|
||||
}
|
||||
};
|
||||
|
||||
run('abc',
|
||||
@@ -408,4 +424,26 @@ Tinytest.add("spacebars - compiler", function (test) {
|
||||
' buf.component(function () { return ((self.lookup("foo")) || EmptyComponent).create({"data": Spacebars.call(self.lookup("bar")), "baz": Spacebars.call(Spacebars.index(self.lookup("x"), "y"))}); });',
|
||||
'}');
|
||||
|
||||
run('{{#foo.bar}}{{/foo.baz}}', {fail: 'Close tag'});
|
||||
run('{{/foo.bar}}{{#foo.bar}}', {fail: 'Unexpected close tag'});
|
||||
|
||||
run('{{#if foo}}bar{{/if}}',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.component(function () { return ((self.lookup("if")) || EmptyComponent).create({"data": Spacebars.call(self.lookup("foo")), "bodyClass": Component.extend({render: function (buf) {',
|
||||
' buf.text("bar");',
|
||||
' }})}); });',
|
||||
'}');
|
||||
|
||||
run('{{#if foo}}bar{{else}}baz{{/if}}',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.component(function () { return ((self.lookup("if")) || EmptyComponent).create({"data": Spacebars.call(self.lookup("foo")), "bodyClass": Component.extend({render: function (buf) {',
|
||||
' buf.text("bar");',
|
||||
' }}), "elseClass": Component.extend({render: function (buf) {',
|
||||
' buf.text("baz");',
|
||||
' }})}); });',
|
||||
'}');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user