mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
moveToNewFile: Update namespace imports (#24612)
This commit is contained in:
parent
75d0852d3e
commit
d8cea359f7
@ -153,6 +153,8 @@ namespace ts.refactor {
|
||||
if (sourceFile === oldFile) continue;
|
||||
for (const statement of sourceFile.statements) {
|
||||
forEachImportInStatement(statement, importNode => {
|
||||
if (checker.getSymbolAtLocation(moduleSpecifierFromImport(importNode)) !== oldFile.symbol) return;
|
||||
|
||||
const shouldMove = (name: Identifier): boolean => {
|
||||
const symbol = isBindingElement(name.parent)
|
||||
? getPropertySymbolFromBindingElement(checker, name.parent as BindingElement & { name: Identifier })
|
||||
@ -163,11 +165,76 @@ namespace ts.refactor {
|
||||
const newModuleSpecifier = combinePaths(getDirectoryPath(moduleSpecifierFromImport(importNode).text), newModuleName);
|
||||
const newImportDeclaration = filterImport(importNode, createLiteral(newModuleSpecifier), shouldMove);
|
||||
if (newImportDeclaration) changes.insertNodeAfter(sourceFile, statement, newImportDeclaration);
|
||||
|
||||
const ns = getNamespaceLikeImport(importNode);
|
||||
if (ns) updateNamespaceLikeImport(changes, sourceFile, checker, movedSymbols, newModuleName, newModuleSpecifier, ns, importNode);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getNamespaceLikeImport(node: SupportedImport): Identifier | undefined {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return node.importClause && node.importClause.namedBindings && node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport ?
|
||||
node.importClause.namedBindings.name : undefined;
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return node.name;
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return tryCast(node.name, isIdentifier);
|
||||
default:
|
||||
return Debug.assertNever(node);
|
||||
}
|
||||
}
|
||||
|
||||
function updateNamespaceLikeImport(
|
||||
changes: textChanges.ChangeTracker,
|
||||
sourceFile: SourceFile,
|
||||
checker: TypeChecker,
|
||||
movedSymbols: ReadonlySymbolSet,
|
||||
newModuleName: string,
|
||||
newModuleSpecifier: string,
|
||||
oldImportId: Identifier,
|
||||
oldImportNode: SupportedImport,
|
||||
): void {
|
||||
const preferredNewNamespaceName = codefix.moduleSpecifierToValidIdentifier(newModuleName, ScriptTarget.ESNext);
|
||||
let needUniqueName = false;
|
||||
const toChange: Identifier[] = [];
|
||||
FindAllReferences.Core.eachSymbolReferenceInFile(oldImportId, checker, sourceFile, ref => {
|
||||
if (!isPropertyAccessExpression(ref.parent)) return;
|
||||
needUniqueName = needUniqueName || !!checker.resolveName(preferredNewNamespaceName, ref, SymbolFlags.All, /*excludeGlobals*/ true);
|
||||
if (movedSymbols.has(checker.getSymbolAtLocation(ref.parent.name)!)) {
|
||||
toChange.push(ref);
|
||||
}
|
||||
});
|
||||
|
||||
if (toChange.length) {
|
||||
const newNamespaceName = needUniqueName ? getUniqueName(preferredNewNamespaceName, sourceFile) : preferredNewNamespaceName;
|
||||
for (const ref of toChange) {
|
||||
changes.replaceNode(sourceFile, ref, createIdentifier(newNamespaceName));
|
||||
}
|
||||
changes.insertNodeAfter(sourceFile, oldImportNode, updateNamespaceLikeImportNode(oldImportNode, newModuleName, newModuleSpecifier));
|
||||
}
|
||||
}
|
||||
|
||||
function updateNamespaceLikeImportNode(node: SupportedImport, newNamespaceName: string, newModuleSpecifier: string): Node {
|
||||
const newNamespaceId = createIdentifier(newNamespaceName);
|
||||
const newModuleString = createLiteral(newModuleSpecifier);
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return createImportDeclaration(
|
||||
/*decorators*/ undefined, /*modifiers*/ undefined,
|
||||
createImportClause(/*name*/ undefined, createNamespaceImport(newNamespaceId)),
|
||||
newModuleString);
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, newNamespaceId, createExternalModuleReference(newModuleString));
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return createVariableDeclaration(newNamespaceId, /*type*/ undefined, createRequireCall(newModuleString));
|
||||
default:
|
||||
return Debug.assertNever(node);
|
||||
}
|
||||
}
|
||||
|
||||
function moduleSpecifierFromImport(i: SupportedImport): StringLiteralLike {
|
||||
return (i.kind === SyntaxKind.ImportDeclaration ? i.moduleSpecifier
|
||||
: i.kind === SyntaxKind.ImportEqualsDeclaration ? i.moduleReference.expression
|
||||
|
||||
49
tests/cases/fourslash/moveToNewFile_namespaceImport.ts
Normal file
49
tests/cases/fourslash/moveToNewFile_namespaceImport.ts
Normal file
@ -0,0 +1,49 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: /a.ts
|
||||
////[|export const x = 0;|]
|
||||
////export const y = 0;
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import * as a from "./a";
|
||||
////a.x;
|
||||
////a.y;
|
||||
|
||||
// @Filename: /c.ts
|
||||
////import a = require("./a");
|
||||
////a.x;
|
||||
////a.y;
|
||||
|
||||
// @Filename: /d.js
|
||||
////const a = require("./a");
|
||||
////a.x;
|
||||
////a.y;
|
||||
|
||||
verify.moveToNewFile({
|
||||
newFileContents: {
|
||||
"/a.ts":
|
||||
`export const y = 0;`,
|
||||
|
||||
"/x.ts":
|
||||
`export const x = 0;`,
|
||||
|
||||
"/b.ts":
|
||||
`import * as a from "./a";
|
||||
import * as x from "./x";
|
||||
x.x;
|
||||
a.y;`,
|
||||
|
||||
"/c.ts":
|
||||
`import a = require("./a");
|
||||
import x = require("./x");
|
||||
x.x;
|
||||
a.y;`,
|
||||
|
||||
"/d.js":
|
||||
`const a = require("./a"), x = require("./x");
|
||||
x.x;
|
||||
a.y;`,
|
||||
},
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user