Skip to content

Commit 4cc0474

Browse files
author
Andy Hanson
committed
Handle shorthand property assignment and re-export
1 parent 61bef3e commit 4cc0474

File tree

2 files changed

+35
-11
lines changed

2 files changed

+35
-11
lines changed

src/services/refactors/convertImport.ts

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,14 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
6767
exportNameToImportName.forEach((name, propertyName) => {
6868
elements.push(createImportSpecifier(name === propertyName ? undefined : createIdentifier(propertyName), createIdentifier(name)));
6969
});
70-
const makeImportDeclaration = (defaultImportName: Identifier | undefined) =>
71-
createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined,
72-
createImportClause(defaultImportName, elements.length ? createNamedImports(elements) : undefined),
73-
toConvert.parent.parent.moduleSpecifier);
7470

71+
const importDecl = toConvert.parent.parent;
7572
if (usedAsNamespaceOrDefault && !allowSyntheticDefaultImports) {
76-
changes.insertNodeAfter(sourceFile, toConvert.parent.parent, makeImportDeclaration(/*defaultImportName*/ undefined));
73+
// Need to leave the namespace import alone
74+
changes.insertNodeAfter(sourceFile, importDecl, updateImport(importDecl, /*defaultImportName*/ undefined, elements));
7775
}
7876
else {
79-
changes.replaceNode(sourceFile, toConvert.parent.parent, makeImportDeclaration(usedAsNamespaceOrDefault ? createIdentifier(toConvert.name.text) : undefined));
77+
changes.replaceNode(sourceFile, importDecl, updateImport(importDecl, usedAsNamespaceOrDefault ? createIdentifier(toConvert.name.text) : undefined, elements));
8078
}
8179
}
8280

@@ -85,14 +83,36 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
8583
// We know the user is using at least ScriptTarget.ES6, and moduleSpecifierToValidIdentifier only cares if we're using ES5+, so just set ScriptTarget.ESNext
8684
const namespaceImportName = generateName(moduleSpecifier && isStringLiteral(moduleSpecifier) ? codefix.moduleSpecifierToValidIdentifier(moduleSpecifier.text, ScriptTarget.ESNext) : "module", usedIdentifiers);
8785

88-
changes.replaceNode(sourceFile, toConvert, createNamespaceImport(createIdentifier(namespaceImportName)));
86+
const neededNamedImports: ImportSpecifier[] = [];
8987

9088
for (const element of toConvert.elements) {
9189
const propertyName = (element.propertyName || element.name).text;
9290
FindAllReferences.Core.eachSymbolReferenceInFile(element.name, checker, sourceFile, id => {
93-
changes.replaceNode(sourceFile, id, createPropertyAccess(createIdentifier(namespaceImportName), propertyName));
91+
const access = createPropertyAccess(createIdentifier(namespaceImportName), propertyName);
92+
if (isShorthandPropertyAssignment(id.parent)) {
93+
changes.replaceNode(sourceFile, id.parent, createPropertyAssignment(id.text, access));
94+
}
95+
else if (isExportSpecifier(id.parent) && !id.parent.propertyName) {
96+
if (!neededNamedImports.some(n => n.name === element.name)) {
97+
neededNamedImports.push(createImportSpecifier(element.propertyName && createIdentifier(element.propertyName.text), createIdentifier(element.name.text)));
98+
}
99+
}
100+
else {
101+
changes.replaceNode(sourceFile, id, access);
102+
}
94103
});
95104
}
105+
106+
changes.replaceNode(sourceFile, toConvert, createNamespaceImport(createIdentifier(namespaceImportName)));
107+
if (neededNamedImports.length) {
108+
const importDecl = toConvert.parent.parent;
109+
changes.insertNodeAfter(sourceFile, toConvert.parent.parent, updateImport(importDecl, /*defaultImportName*/ undefined, neededNamedImports));
110+
}
111+
}
112+
113+
function updateImport(old: ImportDeclaration, defaultImportName: Identifier | undefined, elements: ReadonlyArray<ImportSpecifier> | undefined): ImportDeclaration {
114+
return createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined,
115+
createImportClause(defaultImportName, elements && elements.length ? createNamedImports(elements) : undefined), old.moduleSpecifier);
96116
}
97117

98118
function generateName(name: string, usedIdentifiers: ReadonlyMap<true>): string {

tests/cases/fourslash/refactorConvertImport_namedToNamespace.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
/////*a*/import { x, y as z, T } from "m";/*b*/
44
////const m = 0;
5-
////x;
5+
////const o = { x };
6+
////export { x }; // Need a named import for this
67
////z;
78
////const n: T = 0;
89

@@ -12,9 +13,12 @@ edit.applyRefactor({
1213
actionName: "Convert named imports to namespace import",
1314
actionDescription: "Convert named imports to namespace import",
1415
newContent:
16+
// TODO: GH#23781 (_m.y shouldn't be indented)
1517
`import * as _m from "m";
18+
import { x } from "m";
1619
const m = 0;
17-
_m.x;
18-
_m.y;
20+
const o = { x: _m.x };
21+
export { x }; // Need a named import for this
22+
_m.y;
1923
const n: _m.T = 0;`,
2024
});

0 commit comments

Comments
 (0)