From 6397fec3dcc522ba578c6c4dba3fa6ff9f2eb3a3 Mon Sep 17 00:00:00 2001 From: David Greenspan Date: Thu, 5 Dec 2013 16:06:20 -0800 Subject: [PATCH] Port html_scanner tests; detect duplicate templates Reintroduce a Template.__define__ (like on devel) Remove old compiler tests --- packages/spacebars/spacebars_tests.js | 145 ------------------ packages/templating/global_template_object.js | 12 +- packages/templating/package.js | 2 +- packages/templating/plugin/html2_scanner.js | 6 +- packages/templating/scanner_tests.js | 49 +++--- packages/templating/templating_tests.js | 6 + 6 files changed, 44 insertions(+), 176 deletions(-) diff --git a/packages/spacebars/spacebars_tests.js b/packages/spacebars/spacebars_tests.js index c7ebb6d67b..251019da38 100644 --- a/packages/spacebars/spacebars_tests.js +++ b/packages/spacebars/spacebars_tests.js @@ -332,151 +332,6 @@ Tinytest.add("spacebars - parser", function (test) { {"type":"EndTag","name":"div"}]}); }); -Tinytest.add("spacebars - compiler", function (test) { - - var run = function (input/*, expectedLines*/) { - var expectedLines = Array.prototype.slice.call(arguments, 1); - var expected = expectedLines.join('\n'); - 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', - - 'function (buf) {', - ' buf.write("abc");', - '}'); - - run('abc', - - 'function (buf) {', - ' buf.write("abc");', - '}'); - - // NOTE: These are old tests of code generation from various previous versions - // of the compiler. Once the form of generated code stabilizes, it would be - // nice to have these tests as a way of seeing that code generation is working - // as intended and pretty-printing remains correct, as well as as a form of - // documentation. - /* - run('', - - 'function (buf) {', - ' var self = this;', - ' buf.write("");', - '}'); - - run('', - - 'function (buf) {', - ' var self = this;', - ' buf.write("");', - '}'); - - run('', - - 'function (buf) {', - ' var self = this;', - ' buf.openTag("a", {"foo": function () { return String(Spacebars.call(Spacebars.index(self.lookup("bar"), "baz")) || ""); }});', - '}'); - - run('foo {{bar}} baz', - - 'function (buf) {', - ' var self = this;', - ' buf.text("foo ");', - ' buf.text(function () { return String(Spacebars.call(self.lookup("bar")) || ""); });', - ' buf.text(" baz");', - '}'); - - run('foo {{{bar}}} baz', - - 'function (buf) {', - ' var self = this;', - ' buf.text("foo ");', - ' buf.rawHtml(function () { return String(Spacebars.call(self.lookup("bar")) || ""); });', - ' buf.text(" baz");', - '}'); - - run('foo {{bar "hello"}} baz', - - 'function (buf) {', - ' var self = this;', - ' buf.text("foo ");', - ' buf.text(function () { return String(Spacebars.call(self.lookup("bar"), "hello") || ""); });', - ' buf.text(" baz");', - '}'); - - run('foo {{bar hello}} baz', - - 'function (buf) {', - ' var self = this;', - ' buf.text("foo ");', - ' buf.text(function () { return String(Spacebars.call(self.lookup("bar"), Spacebars.call(self.lookup("hello"))) || ""); });', - ' buf.text(" baz");', - '}'); - - run('{{foo.bar x.y abc=z.w 0 null "hi" z=123.4}}', - - 'function (buf) {', - ' var self = this;', - ' buf.text(function () { return String(Spacebars.call(Spacebars.index(self.lookup("foo"), "bar"), Spacebars.call(Spacebars.index(self.lookup("x"), "y")), 0, null, "hi", {"abc": Spacebars.call(Spacebars.index(self.lookup("z"), "w")), "z": 123.4}) || ""); });', - '}'); - - run('{{> foo bar baz=x.y}}', - - 'function (buf) {', - ' var self = this;', - ' buf.component(function () { return ((self.lookup("foo")) || Component).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")) || Component).create({"data": Spacebars.call(self.lookup("foo")), "content": 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")) || Component).create({"data": Spacebars.call(self.lookup("foo")), "content": Component.extend({render: function (buf) {', - ' buf.text("bar");', - ' }}), "elseContent": Component.extend({render: function (buf) {', - ' buf.text("baz");', - ' }})}); });', - '}'); - */ -}); - Tinytest.add("spacebars - Spacebars.index", function (test) { test.equal(Spacebars.index(null, 'foo'), null); test.equal(Spacebars.index('foo', 'foo'), undefined); diff --git a/packages/templating/global_template_object.js b/packages/templating/global_template_object.js index e1e407a1ae..cf78208e3f 100644 --- a/packages/templating/global_template_object.js +++ b/packages/templating/global_template_object.js @@ -1,3 +1,13 @@ // Create an empty template object. Packages and apps add templates on // to this object. -Template = {}; \ No newline at end of file +Template = {}; + +Template.__define__ = function (templateName, renderFunc) { + if (Template.hasOwnProperty(templateName)) + throw new Error("Can't have two templates named: " + templateName); + + Template[templateName] = UI.Component.extend({ + kind: "Template_" + templateName, + render: renderFunc + }); +}; diff --git a/packages/templating/package.js b/packages/templating/package.js index c0b4410f54..718b37f884 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -45,7 +45,7 @@ Package.on_test(function (api) { 'templating_tests.html2' ], 'client'); api.add_files([ - 'plugin/html_scanner.js', + 'plugin/html2_scanner.js', 'scanner_tests.js' ], 'server'); }); diff --git a/packages/templating/plugin/html2_scanner.js b/packages/templating/plugin/html2_scanner.js index 23736e3ed8..a81494b3bd 100644 --- a/packages/templating/plugin/html2_scanner.js +++ b/packages/templating/plugin/html2_scanner.js @@ -154,10 +154,8 @@ html2_scanner = { sourceName: 'Template "' + name + '"' }); - results.js += "\nTemplate[" + JSON.stringify(name) + - "] = UI.Component.extend({kind: " + - JSON.stringify("Template_" + name) + ", render: " + - renderFuncCode + "});\n"; + results.js += "\nTemplate.__define__(" + JSON.stringify(name) + + ", " + renderFuncCode + ");\n"; } else { // if (hasAttribs) diff --git a/packages/templating/scanner_tests.js b/packages/templating/scanner_tests.js index e55d7b8962..a3cc88e0e3 100644 --- a/packages/templating/scanner_tests.js +++ b/packages/templating/scanner_tests.js @@ -22,12 +22,17 @@ Tinytest.add("templating - html scanner", function (test) { test.fail("Parse error didn't throw exception"); }; - var BODY_PREAMBLE = "Meteor.startup(function(){" + - "document.body.appendChild(Spark.render(" + - "Template.__define__(null,"; - var BODY_POSTAMBLE = ")));});"; - var TEMPLATE_PREAMBLE = "Template.__define__("; - var TEMPLATE_POSTAMBLE = ");\n"; + // returns the appropriate code to put content in the body, + // where content is something simple like the string "Hello" + // (passed in as a source string including the quotes). + var simpleBody = function (content) { + return "\nUI.body2.contentParts.push(UI.Component.extend({render: (function() {\n var self = this;\n return " + content + ";\n})}));\nMeteor.startup(function () { if (! UI.body2.INSTANTIATED) { UI.materialize(UI.body2, document.body); } });\n"; + }; + + // arguments are quoted strings like '"hello"' + var simpleTemplate = function (templateName, content) { + return '\nTemplate.__define__(' + templateName + ', (function() {\n var self = this;\n var __content = self.__content, __elseContent = self.__elseContent;\n return ' + content + ';\n}));\n'; + }; var checkResults = function(results, expectJs, expectHead) { test.equal(results.body, ''); @@ -35,6 +40,8 @@ Tinytest.add("templating - html scanner", function (test) { test.equal(results.head, expectHead || ''); }; + var html_scanner = html2_scanner; + checkError(function() { return html_scanner.scan("asdf"); }, "formatting in HTML template", 1); @@ -42,73 +49,65 @@ Tinytest.add("templating - html scanner", function (test) { // body all on one line checkResults( html_scanner.scan("Hello"), - BODY_PREAMBLE+'Package.handlebars.Handlebars.json_ast_to_func(["Hello"])'+BODY_POSTAMBLE); + simpleBody('"Hello"')); // multi-line body, contents trimmed checkResults( html_scanner.scan("\n\n\n\n\nHello\n\n\n\n\n"), - BODY_PREAMBLE+'Package.handlebars.Handlebars.json_ast_to_func(["Hello"])'+BODY_POSTAMBLE); + simpleBody('"Hello"')); // same as previous, but with various HTML comments checkResults( html_scanner.scan("\n\n\n"+ "\n\nHello\n\n\n\n