Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d8cea35

Browse filesBrowse files
author
Andy
authored
moveToNewFile: Update namespace imports (microsoft#24612)
1 parent 75d0852 commit d8cea35
Copy full SHA for d8cea35

2 files changed

+116Lines changed: 116 additions & 0 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/services/refactors/moveToNewFile.ts‎

Copy file name to clipboardExpand all lines: src/services/refactors/moveToNewFile.ts
+67Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ namespace ts.refactor {
153153
if (sourceFile === oldFile) continue;
154154
for (const statement of sourceFile.statements) {
155155
forEachImportInStatement(statement, importNode => {
156+
if (checker.getSymbolAtLocation(moduleSpecifierFromImport(importNode)) !== oldFile.symbol) return;
157+
156158
const shouldMove = (name: Identifier): boolean => {
157159
const symbol = isBindingElement(name.parent)
158160
? getPropertySymbolFromBindingElement(checker, name.parent as BindingElement & { name: Identifier })
@@ -163,11 +165,76 @@ namespace ts.refactor {
163165
const newModuleSpecifier = combinePaths(getDirectoryPath(moduleSpecifierFromImport(importNode).text), newModuleName);
164166
const newImportDeclaration = filterImport(importNode, createLiteral(newModuleSpecifier), shouldMove);
165167
if (newImportDeclaration) changes.insertNodeAfter(sourceFile, statement, newImportDeclaration);
168+
169+
const ns = getNamespaceLikeImport(importNode);
170+
if (ns) updateNamespaceLikeImport(changes, sourceFile, checker, movedSymbols, newModuleName, newModuleSpecifier, ns, importNode);
166171
});
167172
}
168173
}
169174
}
170175

176+
function getNamespaceLikeImport(node: SupportedImport): Identifier | undefined {
177+
switch (node.kind) {
178+
case SyntaxKind.ImportDeclaration:
179+
return node.importClause && node.importClause.namedBindings && node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport ?
180+
node.importClause.namedBindings.name : undefined;
181+
case SyntaxKind.ImportEqualsDeclaration:
182+
return node.name;
183+
case SyntaxKind.VariableDeclaration:
184+
return tryCast(node.name, isIdentifier);
185+
default:
186+
return Debug.assertNever(node);
187+
}
188+
}
189+
190+
function updateNamespaceLikeImport(
191+
changes: textChanges.ChangeTracker,
192+
sourceFile: SourceFile,
193+
checker: TypeChecker,
194+
movedSymbols: ReadonlySymbolSet,
195+
newModuleName: string,
196+
newModuleSpecifier: string,
197+
oldImportId: Identifier,
198+
oldImportNode: SupportedImport,
199+
): void {
200+
const preferredNewNamespaceName = codefix.moduleSpecifierToValidIdentifier(newModuleName, ScriptTarget.ESNext);
201+
let needUniqueName = false;
202+
const toChange: Identifier[] = [];
203+
FindAllReferences.Core.eachSymbolReferenceInFile(oldImportId, checker, sourceFile, ref => {
204+
if (!isPropertyAccessExpression(ref.parent)) return;
205+
needUniqueName = needUniqueName || !!checker.resolveName(preferredNewNamespaceName, ref, SymbolFlags.All, /*excludeGlobals*/ true);
206+
if (movedSymbols.has(checker.getSymbolAtLocation(ref.parent.name)!)) {
207+
toChange.push(ref);
208+
}
209+
});
210+
211+
if (toChange.length) {
212+
const newNamespaceName = needUniqueName ? getUniqueName(preferredNewNamespaceName, sourceFile) : preferredNewNamespaceName;
213+
for (const ref of toChange) {
214+
changes.replaceNode(sourceFile, ref, createIdentifier(newNamespaceName));
215+
}
216+
changes.insertNodeAfter(sourceFile, oldImportNode, updateNamespaceLikeImportNode(oldImportNode, newModuleName, newModuleSpecifier));
217+
}
218+
}
219+
220+
function updateNamespaceLikeImportNode(node: SupportedImport, newNamespaceName: string, newModuleSpecifier: string): Node {
221+
const newNamespaceId = createIdentifier(newNamespaceName);
222+
const newModuleString = createLiteral(newModuleSpecifier);
223+
switch (node.kind) {
224+
case SyntaxKind.ImportDeclaration:
225+
return createImportDeclaration(
226+
/*decorators*/ undefined, /*modifiers*/ undefined,
227+
createImportClause(/*name*/ undefined, createNamespaceImport(newNamespaceId)),
228+
newModuleString);
229+
case SyntaxKind.ImportEqualsDeclaration:
230+
return createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, newNamespaceId, createExternalModuleReference(newModuleString));
231+
case SyntaxKind.VariableDeclaration:
232+
return createVariableDeclaration(newNamespaceId, /*type*/ undefined, createRequireCall(newModuleString));
233+
default:
234+
return Debug.assertNever(node);
235+
}
236+
}
237+
171238
function moduleSpecifierFromImport(i: SupportedImport): StringLiteralLike {
172239
return (i.kind === SyntaxKind.ImportDeclaration ? i.moduleSpecifier
173240
: i.kind === SyntaxKind.ImportEqualsDeclaration ? i.moduleReference.expression
Collapse file
+49Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @allowJs: true
4+
5+
// @Filename: /a.ts
6+
////[|export const x = 0;|]
7+
////export const y = 0;
8+
9+
// @Filename: /b.ts
10+
////import * as a from "./a";
11+
////a.x;
12+
////a.y;
13+
14+
// @Filename: /c.ts
15+
////import a = require("./a");
16+
////a.x;
17+
////a.y;
18+
19+
// @Filename: /d.js
20+
////const a = require("./a");
21+
////a.x;
22+
////a.y;
23+
24+
verify.moveToNewFile({
25+
newFileContents: {
26+
"/a.ts":
27+
`export const y = 0;`,
28+
29+
"/x.ts":
30+
`export const x = 0;`,
31+
32+
"/b.ts":
33+
`import * as a from "./a";
34+
import * as x from "./x";
35+
x.x;
36+
a.y;`,
37+
38+
"/c.ts":
39+
`import a = require("./a");
40+
import x = require("./x");
41+
x.x;
42+
a.y;`,
43+
44+
"/d.js":
45+
`const a = require("./a"), x = require("./x");
46+
x.x;
47+
a.y;`,
48+
},
49+
});

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.