fix(50654): "Move to a new file" breaks the declaration of referenced variable (#50681)

* fix(50654): remove entire import require call instead of the name

* handle require imports in ts files
This commit is contained in:
Oleksandr T 2022-10-26 03:05:57 +03:00 коммит произвёл GitHub
Родитель 170a17fad5
Коммит 8b1ecdb701
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 109 добавлений и 3 удалений

Просмотреть файл

@ -133,7 +133,7 @@ namespace ts.refactor {
) {
const checker = program.getTypeChecker();
const prologueDirectives = takeWhile(oldFile.statements, isPrologueDirective);
if (!oldFile.externalModuleIndicator && !oldFile.commonJsModuleIndicator) {
if (oldFile.externalModuleIndicator === undefined && oldFile.commonJsModuleIndicator === undefined && usage.oldImportsNeededByNewFile.size() === 0) {
deleteMovedStatements(oldFile, toMove.ranges, changes);
return [...prologueDirectives, ...toMove.all];
}
@ -402,7 +402,13 @@ namespace ts.refactor {
switch (name.kind) {
case SyntaxKind.Identifier:
if (isUnused(name)) {
changes.delete(sourceFile, name);
if (varDecl.initializer && isRequireCall(varDecl.initializer, /*requireStringLiteralLikeArgument*/ true)) {
changes.delete(sourceFile,
isVariableDeclarationList(varDecl.parent) && length(varDecl.parent.declarations) === 1 ? varDecl.parent.parent : varDecl);
}
else {
changes.delete(sourceFile, name);
}
}
break;
case SyntaxKind.ArrayBindingPattern:
@ -641,10 +647,12 @@ namespace ts.refactor {
}
interface ReadonlySymbolSet {
size(): number;
has(symbol: Symbol): boolean;
forEach(cb: (symbol: Symbol) => void): void;
forEachEntry<T>(cb: (symbol: Symbol) => T | undefined): T | undefined;
}
class SymbolSet implements ReadonlySymbolSet {
private map = new Map<string, Symbol>();
add(symbol: Symbol): void {
@ -667,6 +675,9 @@ namespace ts.refactor {
copyEntries(this.map, clone.map);
return clone;
}
size() {
return this.map.size;
}
}
type TopLevelExpressionStatement = ExpressionStatement & { expression: BinaryExpression & { left: PropertyAccessExpression } }; // 'exports.x = ...'
@ -775,7 +786,8 @@ namespace ts.refactor {
if (useEs6Exports) {
return !isExpressionStatement(decl) && hasSyntacticModifier(decl, ModifierFlags.Export) || !!(name && sourceFile.symbol.exports?.has(name.escapedText));
}
return getNamesToExportInCommonJS(decl).some(name => sourceFile.symbol.exports!.has(escapeLeadingUnderscores(name)));
return !!sourceFile.symbol && !!sourceFile.symbol.exports &&
getNamesToExportInCommonJS(decl).some(name => sourceFile.symbol.exports!.has(escapeLeadingUnderscores(name)));
}
function addExport(decl: TopLevelDeclarationStatement, useEs6Exports: boolean): readonly Statement[] | undefined {

Просмотреть файл

@ -0,0 +1,28 @@
/// <reference path="fourslash.ts" />
// @allowJs: true
// @filename: /a.js
////module.exports = 1;
// @filename: /b.js
////var a = require("./a");
////[|function f() {
//// a;
////}|]
verify.noErrors();
verify.moveToNewFile({
newFileContents: {
"/b.js": "",
"/f.js":
`var a = require("./a");
function f() {
a;
}
`,
},
});

Просмотреть файл

@ -0,0 +1,33 @@
/// <reference path="fourslash.ts" />
// @allowJs: true
// @filename: /a.js
////module.exports = 1;
// @filename: /b.js
////var a = require("./a"),
//// b = require("./a"),
//// c = require("./a");
////[|function f() {
//// b;
////}|]
verify.noErrors();
verify.moveToNewFile({
newFileContents: {
"/b.js":
`var a = require("./a"),
c = require("./a");
`,
"/f.js":
`var b = require("./a");
function f() {
b;
}
`,
},
});

Просмотреть файл

@ -0,0 +1,33 @@
/// <reference path="fourslash.ts" />
// @module: commonjs
// @moduleResolution: node
// @filename: /node.d.ts
////declare var module: any;
////declare var require: any;
// @filename: /a.ts
////module.exports = 1;
// @filename: /b.ts
////var a = require("./a");
////[|function f() {
//// a;
////}|]
verify.noErrors();
verify.moveToNewFile({
newFileContents: {
"/b.ts": "",
"/f.ts":
`var a = require("./a");
function f() {
a;
}
`,
},
});