diff --git a/__tests__/tests.ts b/__tests__/tests.ts
index 86ed1fe..faedb60 100644
--- a/__tests__/tests.ts
+++ b/__tests__/tests.ts
@@ -33,6 +33,7 @@ describe('htmlbars-inline-precompile', function () {
});
afterEach(function () {
+ sharedStateToBabel = null;
sinon.restore();
});
@@ -654,13 +655,23 @@ describe('htmlbars-inline-precompile', function () {
);
});
+ let sharedStateToBabel = null as any;
+
let expressionTransform: ExtendedPluginBuilder = (env) => {
return {
name: 'expression-transform',
visitor: {
PathExpression(node, path) {
if (node.original === 'onePlusOne') {
+ let boundName = sharedStateToBabel?.boundName;
+ if (boundName) {
+ env.meta.jsutils.bindVariable(boundName);
+ return env.syntax.builders.path(boundName);
+ }
let name = env.meta.jsutils.bindExpression('1+1', path, { nameHint: 'two' });
+ if (sharedStateToBabel) {
+ sharedStateToBabel.boundName = name;
+ }
return env.syntax.builders.path(name);
}
return undefined;
@@ -1314,6 +1325,47 @@ describe('htmlbars-inline-precompile', function () {
`);
});
+ it('can reuse bindings', function () {
+ plugins = [
+ [HTMLBarsInlinePrecompile, { targetFormat: 'hbs', transforms: [expressionTransform] }],
+ ];
+
+ sharedStateToBabel = {};
+
+ let transformed = transform(stripIndent`
+ import { precompileTemplate } from '@ember/template-compilation';
+ import Message from 'message';
+ const template = precompileTemplate('', {
+ scope: () => ({
+ Message
+ })
+ });
+ const template2 = precompileTemplate('', {
+ scope: () => ({
+ Message
+ })
+ });
+ `);
+
+ expect(transformed).toEqualCode(`
+ import { precompileTemplate } from '@ember/template-compilation';
+ import Message from 'message';
+ let two = 1 + 1;
+ const template = precompileTemplate("", {
+ scope: () => ({
+ Message,
+ two
+ })
+ });
+ const template2 = precompileTemplate("", {
+ scope: () => ({
+ Message,
+ two
+ })
+ });
+ `);
+ });
+
it('adds new locals to preexisting renamed scope', function () {
plugins = [
[HTMLBarsInlinePrecompile, { targetFormat: 'hbs', transforms: [expressionTransform] }],
diff --git a/src/js-utils.ts b/src/js-utils.ts
index f2468da..f72e5df 100644
--- a/src/js-utils.ts
+++ b/src/js-utils.ts
@@ -16,7 +16,7 @@ export class JSUtils {
#babel: typeof Babel;
#state: State;
#template: NodePath;
- #addedBinding: (name: string) => void;
+ #addedBinding: (name: string, jsName?: string) => void;
#importer: ImportUtil;
constructor(
@@ -84,6 +84,20 @@ export class JSUtils {
return name;
}
+ /**
+ * Allows (re)use of binding that you already have in the js code or created with bindExpression
+ * Especially useful if you have a custom transform that creates a binding that you want to reuse
+ *
+ * @param hbsName the name you are using in your template to access the binding
+ * @param jsName the name of a js variable
+ *
+ * @return The name you can use in your template to access the binding.
+ */
+ bindVariable(hbsName: string, jsName?: string) {
+ this.#addedBinding(hbsName, jsName);
+ return hbsName;
+ }
+
#emitStatement(statement: T): NodePath {
if (this.#state.lastInsertedPath) {
this.#state.lastInsertedPath = this.#state.lastInsertedPath.insertAfter(statement)[0];