Skip to content
This repository has been archived by the owner on Dec 8, 2024. It is now read-only.

Commit

Permalink
Add ability to pass static options to transpilation.
Browse files Browse the repository at this point in the history
This allows consumers to specify additional options during compilation,
for example you might need to ensure that the compiled template has a
moduleName set (e.g. if you are testing an AST plugin that needs to know
the compiled templates module name).

Note: this functionality is only possible with the `CallExpression`
version of `hbs`. This is because there is no way to pass additional
arguments to a `TaggedTemplateExpression`.
  • Loading branch information
rwjblue committed Aug 30, 2019
1 parent cbe5718 commit cb5e610
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 16 deletions.
63 changes: 51 additions & 12 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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));
},
}
};
Expand Down
21 changes: 17 additions & 4 deletions tests/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}\`;`);
Expand Down Expand Up @@ -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/);
});
});
});

0 comments on commit cb5e610

Please sign in to comment.