Skip to content

Commit cd3ce26

Browse files
authored
Merge pull request #34 from patricklx/patch-4
fix gts ts imports issue
2 parents 5fceb59 + 7a9dcaa commit cd3ce26

File tree

2 files changed

+37
-54
lines changed

2 files changed

+37
-54
lines changed

__tests__/tests.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ describe('htmlbars-inline-precompile', function () {
421421
);
422422

423423
expect(transformed).toEqualCode(`
424-
define(["@ember/template-compilation", "@ember/template-factory"], function (_templateCompilation, _templateFactory) {
424+
define(["@ember/template-factory"], function (_templateFactory) {
425425
"use strict";
426426
427427
var compiled = (0, _templateFactory.createTemplateFactory)(
@@ -1845,6 +1845,15 @@ describe('htmlbars-inline-precompile', function () {
18451845
});
18461846

18471847
it('interoperates correctly with @babel/plugin-transform-typescript when handling locals with wire target', function () {
1848+
let imports: string[] = [];
1849+
let otherPlugin: babel.PluginObj = {
1850+
name: 'other',
1851+
visitor: {
1852+
ImportDeclaration(path) {
1853+
imports.push(path.node.source.value);
1854+
},
1855+
},
1856+
};
18481857
plugins = [
18491858
[
18501859
HTMLBarsInlinePrecompile,
@@ -1853,6 +1862,7 @@ describe('htmlbars-inline-precompile', function () {
18531862
targetFormat: 'wire',
18541863
},
18551864
],
1865+
otherPlugin,
18561866
TransformTypescript,
18571867
];
18581868

@@ -1863,6 +1873,12 @@ describe('htmlbars-inline-precompile', function () {
18631873
`
18641874
);
18651875

1876+
expect(imports.length).toEqual(4);
1877+
expect(imports[0]).toEqual('somewhere');
1878+
expect(imports[1]).toEqual('@ember/template-factory');
1879+
expect(imports[2]).toEqual('@ember/component');
1880+
expect(imports[3]).toEqual('@ember/component/template-only');
1881+
18661882
expect(normalizeWireFormat(transformed)).toEqualCode(`
18671883
import HelloWorld from 'somewhere';
18681884
import { createTemplateFactory } from "@ember/template-factory";

src/plugin.ts

+20-53
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ interface State<EnvSpecificOptions> {
147147
lastInsertedPath: NodePath<t.Statement> | undefined;
148148
filename: string;
149149
recursionGuard: Set<unknown>;
150-
originalImportedNames: Map<string, [string, string]>;
151150
}
152151

153152
export function makePlugin<EnvSpecificOptions>(loadOptions: (opts: EnvSpecificOptions) => Options) {
@@ -156,26 +155,7 @@ export function makePlugin<EnvSpecificOptions>(loadOptions: (opts: EnvSpecificOp
156155
): Babel.PluginObj<State<EnvSpecificOptions>> {
157156
let t = babel.types;
158157

159-
return {
160-
pre(this: State<EnvSpecificOptions>, file) {
161-
// Remember the available set of imported names very early here in <pre>
162-
// so that when other plugins (particularly
163-
// @babel/plugin-transform-typescript) drop "unused" imports in their
164-
// own Program.enter we still know about them. If we want to use them
165-
// from inside a template, they weren't really unused and we can ensure
166-
// they continue to exist.
167-
this.originalImportedNames = new Map();
168-
for (let statement of file.ast.program.body) {
169-
if (statement.type === 'ImportDeclaration') {
170-
for (let specifier of statement.specifiers) {
171-
this.originalImportedNames.set(specifier.local.name, [
172-
statement.source.value,
173-
importedName(specifier),
174-
]);
175-
}
176-
}
177-
}
178-
},
158+
const plugin = {
179159
visitor: {
180160
Program: {
181161
enter(path: NodePath<t.Program>, state: State<EnvSpecificOptions>) {
@@ -335,6 +315,15 @@ export function makePlugin<EnvSpecificOptions>(loadOptions: (opts: EnvSpecificOp
335315
},
336316
},
337317
};
318+
319+
return {
320+
pre(this: State<EnvSpecificOptions>, file) {
321+
// run our processing in pre so that imports for gts
322+
// are kept for other plugins.
323+
babel.traverse(file.ast, plugin.visitor, file.scope, this);
324+
},
325+
visitor: {},
326+
};
338327
} as (babel: typeof Babel) => Babel.PluginObj<unknown>;
339328
}
340329

@@ -513,7 +502,6 @@ function insertCompiledTemplate<EnvSpecificOptions>(
513502
configFile: false,
514503
}) as t.File;
515504

516-
ensureImportedNames(target, scopeLocals, state.util, state.originalImportedNames);
517505
remapIdentifiers(precompileResultAST, babel, scopeLocals);
518506

519507
let templateExpression = (precompileResultAST.program.body[0] as t.VariableDeclaration)
@@ -548,6 +536,7 @@ function insertCompiledTemplate<EnvSpecificOptions>(
548536
);
549537
}
550538
target.replaceWith(expression);
539+
target.scope.crawl();
551540
}
552541

553542
function insertTransformedTemplate<EnvSpecificOptions>(
@@ -572,15 +561,16 @@ function insertTransformedTemplate<EnvSpecificOptions>(
572561
);
573562
let ast = preprocess(template, { ...options, mode: 'codemod' });
574563
let transformed = print(ast, { entityEncoding: 'raw' });
564+
let needsScopeCrawl = false;
575565
if (target.isCallExpression()) {
576566
(target.get('arguments.0') as NodePath<t.Node>).replaceWith(t.stringLiteral(transformed));
577567
if (!scopeLocals.isEmpty()) {
578568
if (!formatOptions.enableScope) {
579569
maybePruneImport(state.util, target.get('callee'));
580570
target.set('callee', precompileTemplate(state.util, target));
581571
}
582-
ensureImportedNames(target, scopeLocals, state.util, state.originalImportedNames);
583572
updateScope(babel, target, scopeLocals);
573+
needsScopeCrawl = true;
584574
}
585575

586576
if (formatOptions.rfc931Support === 'polyfilled') {
@@ -590,7 +580,7 @@ function insertTransformedTemplate<EnvSpecificOptions>(
590580
removeEvalAndScope(target);
591581
target.node.arguments = target.node.arguments.slice(0, 2);
592582
state.recursionGuard.add(target.node);
593-
target.replaceWith(
583+
target = target.replaceWith(
594584
t.callExpression(state.util.import(target, '@ember/component', 'setComponentTemplate'), [
595585
target.node,
596586
backingClass?.node ??
@@ -604,7 +594,11 @@ function insertTransformedTemplate<EnvSpecificOptions>(
604594
[]
605595
),
606596
])
607-
);
597+
)[0];
598+
needsScopeCrawl = true;
599+
}
600+
if (needsScopeCrawl) {
601+
target.scope.crawl();
608602
}
609603
} else {
610604
if (!scopeLocals.isEmpty()) {
@@ -614,8 +608,8 @@ function insertTransformedTemplate<EnvSpecificOptions>(
614608
let newCall = target.replaceWith(
615609
t.callExpression(precompileTemplate(state.util, target), [t.stringLiteral(transformed)])
616610
)[0];
617-
ensureImportedNames(newCall, scopeLocals, state.util, state.originalImportedNames);
618611
updateScope(babel, newCall, scopeLocals);
612+
newCall.scope.crawl();
619613
} else {
620614
(target.get('quasi').get('quasis.0') as NodePath<t.TemplateElement>).replaceWith(
621615
t.templateElement({ raw: transformed })
@@ -752,31 +746,4 @@ function name(node: t.StringLiteral | t.Identifier) {
752746
}
753747
}
754748

755-
function ensureImportedNames(
756-
target: NodePath<t.Node>,
757-
scopeLocals: ScopeLocals,
758-
util: ImportUtil,
759-
originalImportedNames: Map<string, [string, string]>
760-
) {
761-
for (let [nameInTemplate, identifier] of scopeLocals.entries()) {
762-
if (!target.scope.getBinding(identifier)) {
763-
let available = originalImportedNames.get(identifier);
764-
if (available) {
765-
let newIdent = util.import(target, available[0], available[1], identifier);
766-
scopeLocals.add(nameInTemplate, newIdent.name);
767-
}
768-
}
769-
}
770-
}
771-
772-
function importedName(node: t.ImportDeclaration['specifiers'][number]): string {
773-
if (node.type === 'ImportDefaultSpecifier') {
774-
return 'default';
775-
} else if (node.type === 'ImportNamespaceSpecifier') {
776-
return '*';
777-
} else {
778-
return name(node.imported);
779-
}
780-
}
781-
782749
export default makePlugin<Options>((options) => options);

0 commit comments

Comments
 (0)