diff --git a/index.js b/index.js index 8832e903..da4f5a38 100644 --- a/index.js +++ b/index.js @@ -5,16 +5,37 @@ const parseModuleName = require('./lib/parse-module-name'); module.exports = function(babel) { let t = babel.types; - function compileTemplate(precompile, template) { - let options = { - contents: template - } + function compileTemplate(precompile, template, _options) { + let options = Object.assign({ contents: template }, _options); let compiledTemplateString = `Ember.HTMLBars.template(${precompile(template, options)})`; return compiledTemplateString; } + function parseObjectExpression(buildError, node) { + let result = {}; + + node.properties.forEach(property => { + if (property.computed || property.key.type !== "Identifier") { + throw buildError("hbs can only accept static options"); + } + + let value; + if (property.value.type === "ObjectExpression") { + value = parseObjectExpression(buildError, property.value); + } else if (["StringLiteral", "NumericLiteral", "BooleanLiteral"].indexOf(property.value.type) > -1) { + value = property.value.value; + } else { + throw buildError("hbs can only accept static options"); + } + + result[property.key.name] = value; + }); + + return result; + } + return { visitor: { ImportDeclaration(path, state) { @@ -63,7 +84,7 @@ module.exports = function(babel) { options.meta.moduleName = moduleName; } - path.replaceWithSourceString(compileTemplate(state.opts.precompile, template, state.file.opts.filename)); + path.replaceWithSourceString(compileTemplate(state.opts.precompile, template)); }, CallExpression(path, state) { @@ -74,17 +95,35 @@ module.exports = function(babel) { return; } - let argumentErrorMsg = "hbs should be invoked with a single argument: the template string"; - if (path.node.arguments.length !== 1) { - throw path.buildCodeFrameError(argumentErrorMsg); + let options; + + let template = path.node.arguments[0]; + if (template === undefined || typeof template.value !== "string") { + throw path.buildCodeFrameError("hbs should be invoked with at least a single argument: the template string"); } - let template = path.node.arguments[0].value; - if (typeof template !== "string") { - throw path.buildCodeFrameError(argumentErrorMsg); + switch (path.node.arguments.length) { + case 0: + throw path.buildCodeFrameError("hbs should be invoked with at least a single argument: the template string"); + case 1: + break; + case 2: { + let astOptions = path.node.arguments[1]; + if (astOptions.type !== "ObjectExpression") { + throw path.buildCodeFrameError("hbs can only be invoked with 2 arguments: the template string, and any static options"); + } + + options = parseObjectExpression(path.buildCodeFrameError.bind(path), astOptions); + + break; + } + default: + throw path.buildCodeFrameError("hbs can only be invoked with 2 arguments: the template string, and any static options"); } - path.replaceWithSourceString(compileTemplate(state.opts.precompile, template, state.file.opts.filename)); + let { precompile } = state.opts; + + path.replaceWithSourceString(compileTemplate(precompile, template.value, options)); }, } }; diff --git a/tests/tests.js b/tests/tests.js index 887622c3..bdb30d63 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -38,6 +38,19 @@ describe("htmlbars-inline-precompile", function() { }); }); + it('allows static userland options when used as a call expression', function() { + let source = 'hello'; + transform(`import hbs from 'htmlbars-inline-precompile';\nvar compiled = hbs('${source}', { parseOptions: { srcName: 'bar.hbs' }, moduleName: 'foo/bar.hbs', xyz: 123, qux: true });`); + + expect(optionsReceived).toEqual({ + contents: source, + parseOptions: { srcName: 'bar.hbs' }, + moduleName: 'foo/bar.hbs', + xyz: 123, + qux: true + }); + }); + it('passes options when used as a tagged template string', function() { let source = 'hello'; transform(`import hbs from 'htmlbars-inline-precompile';\nvar compiled = hbs\`${source}\`;`); @@ -138,19 +151,19 @@ describe("htmlbars-inline-precompile", function() { expect(transformed).toEqual("var compiled = Ember.HTMLBars.template(precompiled(hello));", "tagged template is replaced"); }); - it("warns when more than one argument is passed", function() { + it("warns when the second argument is not an object", function() { expect(() => transform("import hbs from 'htmlbars-inline-precompile';\nvar compiled = hbs('first', 'second');")) - .toThrow(/hbs should be invoked with a single argument: the template string/); + .toThrow(/hbs can only be invoked with 2 arguments: the template string, and any static options/); }); it("warns when argument is not a string", function() { expect(() => transform("import hbs from 'htmlbars-inline-precompile';\nvar compiled = hbs(123);")) - .toThrow(/hbs should be invoked with a single argument: the template string/); + .toThrow(/hbs should be invoked with at least a single argument: the template string/); }); it("warns when no argument is passed", function() { expect(() => transform("import hbs from 'htmlbars-inline-precompile';\nvar compiled = hbs();")) - .toThrow(/hbs should be invoked with a single argument: the template string/); + .toThrow(/hbs should be invoked with at least a single argument: the template string/); }); }); });