Skip to content

Commit 5e294ec

Browse files
Alanhansl
Alan
authored andcommitted
fix(@ngtools/webpack): drop only unused default import when used with named imports
At the moment when having a default import together with a named import example: ``` import abc, { def } from './foo'; ``` And the default import becomes unused it will drop the entire node which will caused used named imports to be dropped as well.
1 parent 5e6b42c commit 5e294ec

File tree

1 file changed

+33
-16
lines changed

1 file changed

+33
-16
lines changed

packages/ngtools/webpack/src/transformers/elide_imports.ts

+33-16
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export function elideImports(
3131
// Collect all imports and used identifiers
3232
const specialCaseNames = new Set<string>();
3333
const usedSymbols = new Set<ts.Symbol>();
34-
const imports = [] as ts.ImportDeclaration[];
34+
const imports: ts.ImportDeclaration[] = [];
3535
ts.forEachChild(sourceFile, function visit(node) {
3636
// Skip removed nodes
3737
if (removedNodes.includes(node)) {
@@ -84,28 +84,45 @@ export function elideImports(
8484
continue;
8585
}
8686

87-
if (node.importClause.name) {
88-
// "import XYZ from 'abc';"
89-
if (isUnused(node.importClause.name)) {
90-
ops.push(new RemoveNodeOperation(sourceFile, node));
91-
}
92-
} else if (node.importClause.namedBindings
93-
&& ts.isNamespaceImport(node.importClause.namedBindings)) {
87+
const namedBindings = node.importClause.namedBindings;
88+
89+
if (namedBindings && ts.isNamespaceImport(namedBindings)) {
9490
// "import * as XYZ from 'abc';"
95-
if (isUnused(node.importClause.namedBindings.name)) {
91+
if (isUnused(namedBindings.name)) {
9692
ops.push(new RemoveNodeOperation(sourceFile, node));
9793
}
98-
} else if (node.importClause.namedBindings
99-
&& ts.isNamedImports(node.importClause.namedBindings)) {
100-
// "import { XYZ, ... } from 'abc';"
94+
} else {
10195
const specifierOps = [];
102-
for (const specifier of node.importClause.namedBindings.elements) {
103-
if (isUnused(specifier.name)) {
104-
specifierOps.push(new RemoveNodeOperation(sourceFile, specifier));
96+
let clausesCount = 0;
97+
98+
// "import { XYZ, ... } from 'abc';"
99+
if (namedBindings && ts.isNamedImports(namedBindings)) {
100+
let removedClausesCount = 0;
101+
clausesCount += namedBindings.elements.length;
102+
103+
for (const specifier of namedBindings.elements) {
104+
if (isUnused(specifier.name)) {
105+
removedClausesCount++;
106+
// in case we don't have any more namedImports we should remove the parent ie the {}
107+
const nodeToRemove = clausesCount === removedClausesCount
108+
? specifier.parent
109+
: specifier;
110+
111+
specifierOps.push(new RemoveNodeOperation(sourceFile, nodeToRemove));
112+
}
113+
}
114+
}
115+
116+
// "import XYZ from 'abc';"
117+
if (node.importClause.name) {
118+
clausesCount++;
119+
120+
if (isUnused(node.importClause.name)) {
121+
specifierOps.push(new RemoveNodeOperation(sourceFile, node.importClause.name));
105122
}
106123
}
107124

108-
if (specifierOps.length === node.importClause.namedBindings.elements.length) {
125+
if (specifierOps.length === clausesCount) {
109126
ops.push(new RemoveNodeOperation(sourceFile, node));
110127
} else {
111128
ops.push(...specifierOps);

0 commit comments

Comments
 (0)