Skip to content

Commit 95a7a04

Browse files
committed
allow reuse of bindings
1 parent cdbabfd commit 95a7a04

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

__tests__/tests.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ describe('htmlbars-inline-precompile', function () {
3333
});
3434

3535
afterEach(function () {
36+
sharedStateToBabel = null;
3637
sinon.restore();
3738
});
3839

@@ -654,13 +655,23 @@ describe('htmlbars-inline-precompile', function () {
654655
);
655656
});
656657

658+
let sharedStateToBabel = null as any;
659+
657660
let expressionTransform: ExtendedPluginBuilder = (env) => {
658661
return {
659662
name: 'expression-transform',
660663
visitor: {
661664
PathExpression(node, path) {
662665
if (node.original === 'onePlusOne') {
666+
let boundName = sharedStateToBabel?.boundName;
667+
if (boundName) {
668+
env.meta.jsutils.bindVariable(boundName);
669+
return env.syntax.builders.path(boundName);
670+
}
663671
let name = env.meta.jsutils.bindExpression('1+1', path, { nameHint: 'two' });
672+
if (sharedStateToBabel) {
673+
sharedStateToBabel.boundName = name;
674+
}
664675
return env.syntax.builders.path(name);
665676
}
666677
return undefined;
@@ -1314,6 +1325,47 @@ describe('htmlbars-inline-precompile', function () {
13141325
`);
13151326
});
13161327

1328+
it('can reuse bindings', function () {
1329+
plugins = [
1330+
[HTMLBarsInlinePrecompile, { targetFormat: 'hbs', transforms: [expressionTransform] }],
1331+
];
1332+
1333+
sharedStateToBabel = {};
1334+
1335+
let transformed = transform(stripIndent`
1336+
import { precompileTemplate } from '@ember/template-compilation';
1337+
import Message from 'message';
1338+
const template = precompileTemplate('<Message @text={{onePlusOne}} />', {
1339+
scope: () => ({
1340+
Message
1341+
})
1342+
});
1343+
const template2 = precompileTemplate('<Message @text={{onePlusOne}} />', {
1344+
scope: () => ({
1345+
Message
1346+
})
1347+
});
1348+
`);
1349+
1350+
expect(transformed).toEqualCode(`
1351+
import { precompileTemplate } from '@ember/template-compilation';
1352+
import Message from 'message';
1353+
let two = 1 + 1;
1354+
const template = precompileTemplate("<Message @text={{two}} />", {
1355+
scope: () => ({
1356+
Message,
1357+
two
1358+
})
1359+
});
1360+
const template2 = precompileTemplate("<Message @text={{two}} />", {
1361+
scope: () => ({
1362+
Message,
1363+
two
1364+
})
1365+
});
1366+
`);
1367+
});
1368+
13171369
it('adds new locals to preexisting renamed scope', function () {
13181370
plugins = [
13191371
[HTMLBarsInlinePrecompile, { targetFormat: 'hbs', transforms: [expressionTransform] }],

src/js-utils.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export class JSUtils {
1616
#babel: typeof Babel;
1717
#state: State;
1818
#template: NodePath<t.Expression>;
19-
#addedBinding: (name: string) => void;
19+
#addedBinding: (name: string, jsName?: string) => void;
2020
#importer: ImportUtil;
2121

2222
constructor(
@@ -84,6 +84,20 @@ export class JSUtils {
8484
return name;
8585
}
8686

87+
/**
88+
* Allows (re)use of binding that you already have in the js code or created with bindExpression
89+
* Especially useful if you have a custom transform that creates a binding that you want to reuse
90+
*
91+
* @param hbsName the name you are using in your template to access the binding
92+
* @param jsName the name of a js variable
93+
*
94+
* @return The name you can use in your template to access the binding.
95+
*/
96+
bindVariable(hbsName: string, jsName?: string) {
97+
this.#addedBinding(hbsName, jsName);
98+
return hbsName;
99+
}
100+
87101
#emitStatement<T extends t.Statement>(statement: T): NodePath<T> {
88102
if (this.#state.lastInsertedPath) {
89103
this.#state.lastInsertedPath = this.#state.lastInsertedPath.insertAfter(statement)[0];

0 commit comments

Comments
 (0)