Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions __tests__/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,37 @@ describe('htmlbars-inline-precompile', function () {
expect(transformed).toContain(`import two from "my-library"`);
});

it('reuses existing imports when possible', () => {
precompile = runASTTransform(compiler, importTransform);

let transformed = transform(stripIndent`
import { precompileTemplate } from '@ember/template-compilation';
export default function() {
const template = precompileTemplate('{{onePlusOne}}{{onePlusOne}}');
}
`);

expect(transformed).toContain(`{{two}}{{two}}`);
expect(transformed).toContain(`locals: [two]`);
expect(transformed).toContain(`import two from "my-library"`);
});

it('rebinds existing imports when necessary', () => {
precompile = runASTTransform(compiler, importTransform);

let transformed = transform(stripIndent`
import { precompileTemplate } from '@ember/template-compilation';
export default function() {
const template = precompileTemplate('{{onePlusOne}}{{#let "twice" as |two|}}{{onePlusOne}}{{/let}}');
}
`);

expect(transformed).toContain(`{{two}}{{#let "twice" as |two|}}{{two0}}{{/let}}`);
expect(transformed).toContain(`locals: [two, two0]`);
expect(transformed).toContain(`import two from "my-library"`);
expect(transformed).toContain('let two0 = two');
});

it('does not smash existing js binding for expression', function () {
precompile = runASTTransform(compiler, expressionTransform);

Expand Down Expand Up @@ -751,6 +782,22 @@ describe('htmlbars-inline-precompile', function () {
expect(transformed).toContain(`let two = 1 + 1`);
});

it('does not smash other previously-bound expressions with new ones', () => {
precompile = runASTTransform(compiler, expressionTransform);

let transformed = transform(stripIndent`
import { precompileTemplate } from '@ember/template-compilation';
export default function() {
const template = precompileTemplate('{{onePlusOne}}{{onePlusOne}}');
}
`);

expect(transformed).toContain(`{{two}}{{two0}}`);
expect(transformed).toContain(`locals: [two, two0]`);
expect(transformed).toContain(`let two = 1 + 1`);
expect(transformed).toContain(`let two0 = 1 + 1`);
});

it('can bind expressions that need imports', function () {
let nowTransform: ASTPluginBuilder<WithJSUtils<ASTPluginEnvironment>> = (env) => {
return {
Expand Down
19 changes: 16 additions & 3 deletions src/js-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ export class JSUtils {
let name = unusedNameLike(
opts?.nameHint ?? 'a',
(candidate) =>
this.#template.scope.hasBinding(candidate) || astNodeHasBinding(target, candidate)
this.#template.scope.hasBinding(candidate) ||
this.#locals.includes(candidate) ||
astNodeHasBinding(target, candidate)
);
let t = this.#babel.types;
this.#emitStatement(
Expand Down Expand Up @@ -98,8 +100,19 @@ export class JSUtils {
opts?.nameHint
);

let identifier = unusedNameLike(importedIdentifier.name, (candidate) =>
astNodeHasBinding(target, candidate)
// If we're already referencing the imported name from the outer scope and
// it's not shadowed at our target location in the template, we can reuse
// the existing import.
if (
this.#locals.includes(importedIdentifier.name) &&
!astNodeHasBinding(target, importedIdentifier.name)
) {
return importedIdentifier.name;
}

let identifier = unusedNameLike(
importedIdentifier.name,
(candidate) => this.#locals.includes(candidate) || astNodeHasBinding(target, candidate)
);
if (identifier !== importedIdentifier.name) {
// The importedIdentifier that we have in Javascript is not usable within
Expand Down