diff --git a/packages/templating/package.js b/packages/templating/package.js index be78263292..4b07677924 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -9,14 +9,18 @@ Package.describe({ // registry and a default templating system, ideally per-package. Package.registerBuildPlugin({ - name: "compileTemplates", + name: "compileTemplatesBatch", // minifiers is a weak dependency of spacebars-compiler; adding it here // ensures that the output is minified. (Having it as a weak dependency means // that we don't ship uglify etc with built apps just because // boilerplate-generator uses spacebars-compiler.) // XXX maybe uglify should be applied by this plugin instead of via magic // weak dependency. - use: ['minifiers', 'spacebars-compiler'], + use: [ + 'minifiers', + 'spacebars-compiler', + 'compiler-plugin' + ], sources: [ 'plugin/html_scanner.js', 'plugin/compile-templates.js' diff --git a/packages/templating/plugin/compile-templates.js b/packages/templating/plugin/compile-templates.js index edd4e538a6..9c23549c95 100644 --- a/packages/templating/plugin/compile-templates.js +++ b/packages/templating/plugin/compile-templates.js @@ -1,52 +1,89 @@ var path = Npm.require('path'); -var doHTMLScanning = function (compileStep, htmlScanner) { - // XXX the way we deal with encodings here is sloppy .. should get - // religion on that - var contents = compileStep.read().toString('utf8'); +function TemplateCompiler () {} +TemplateCompiler.prototype.processFilesForTarget = function (files) { + var bodyAttrs = {}; + var bodyAttrsOrigin = {}; + + files.forEach(function (file) { + var scanned = doHTMLScanning(file, html_scanner); + Object.keys(scanned.bodyAttrs).forEach(function (attr) { + var val = scanned.bodyAttrs[attr]; + if (bodyAttrs.hasOwnProperty(attr) && bodyAttrs[attr] !== val) { + // two conflicting attributes on tags in two different template + // files + var conflictingFilesStr = [bodyAttrsOrigin[attr], file].map(function (f) { + return f.getPathInPackage(); + }).join(', '); + + file.error({ + message: [ + " declarations have conflicting values for the '", + attr, + "' attribute in the following files: ", + conflictingFilesStr, + "." + ].join('') + }); + return; + } + + bodyAttrs[attr] = val; + bodyAttrsOrigin[attr] = file; + }); + }); +}; + +var doHTMLScanning = function (inputFile, htmlScanner) { + var contents = inputFile.getContentsAsString(); try { - var results = htmlScanner.scan(contents, compileStep.inputPath); + var results = htmlScanner.scan(contents, inputFile.getPathInPackage()); } catch (e) { - if (e instanceof htmlScanner.ParseError) { - compileStep.error({ + if ((e instanceof htmlScanner.ParseError) || (e instanceof htmlScanner.BodyAttrsError)) { + inputFile.error({ message: e.message, - sourcePath: compileStep.inputPath, line: e.line }); - return; - } else + return null; + } else { throw e; + } } if (results.head) - compileStep.appendDocument({ section: "head", data: results.head }); + inputFile.addHtml({ section: "head", data: results.head }); if (results.body) - compileStep.appendDocument({ section: "body", data: results.body }); + inputFile.addHtml({ section: "body", data: results.body }); if (results.js) { - var path_part = path.dirname(compileStep.inputPath); - if (path_part === '.') - path_part = ''; - if (path_part.length && path_part !== path.sep) - path_part = path_part + path.sep; - var ext = path.extname(compileStep.inputPath); - var basename = path.basename(compileStep.inputPath, ext); + var filePath = inputFile.getPathInPackage(); + var pathPart = path.dirname(filePath); + if (pathPart === '.') + pathPart = ''; + if (pathPart.length && pathPart !== path.sep) + pathPart = pathPart + path.sep; + var ext = path.extname(filePath); + var basename = path.basename(filePath, ext); // XXX generate a source map - compileStep.addJavaScript({ - path: path.join(path_part, "template." + basename + ".js"), - sourcePath: compileStep.inputPath, + inputFile.addJavaScript({ + path: path.join(pathPart, "template." + basename + ".js"), data: results.js }); } + + return { + bodyAttrs: results.bodyAttrs + }; }; -// XXX BBP rewrite to registerCompiler -Plugin.registerSourceHandler( - "html", {isTemplate: true, archMatching: 'web'}, - function (compileStep) { - doHTMLScanning(compileStep, html_scanner); - } -); +Plugin.registerCompiler({ + extensions: ['html'], + archMatching: 'web', + isTemplate: true +}, function () { + return new TemplateCompiler(); +}); + diff --git a/packages/templating/plugin/html_scanner.js b/packages/templating/plugin/html_scanner.js index 5fca649a3a..51884f9fcd 100644 --- a/packages/templating/plugin/html_scanner.js +++ b/packages/templating/plugin/html_scanner.js @@ -7,10 +7,8 @@ html_scanner = { // and ignores top-level HTML comments. // Has fields 'message', 'line', 'file' - ParseError: function () { - }, - - bodyAttributes : [], + ParseError: function () {}, + BodyAttrsError: function () {}, scan: function (contents, source_name) { var rest = contents; @@ -21,14 +19,23 @@ html_scanner = { index += amount; }; - var throwParseError = function (msg, overrideIndex) { - var ret = new html_scanner.ParseError; - ret.message = msg || "bad formatting in template file"; + var throwSpecialError = function (msg, errorClass, overrideIndex) { + var ret = new errorClass; + ret.message = msg; ret.file = source_name; var theIndex = (typeof overrideIndex === 'number' ? overrideIndex : index); ret.line = contents.substring(0, theIndex).split('\n').length; throw ret; }; + var throwParseError = function (msg, overrideIndex) { + throwSpecialError( + msg || "bad formatting in template file", + html_scanner.ParseError, + overrideIndex); + }; + var throwBodyAttrsError = function (msg) { + throwSpecialError(msg, html_scanner.BodyAttrsError); + }; var results = html_scanner._initResults(); var rOpenTag = /^((<(template|head|body)\b)|(