Skip to content

Commit bc570cd

Browse files
author
Andy
authored
moveToNewFile: Respect UserPreferences#quote (microsoft#24365)
1 parent 22252d5 commit bc570cd

File tree

8 files changed

+60
-52
lines changed

8 files changed

+60
-52
lines changed

src/harness/fourslash.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3130,7 +3130,7 @@ Actual: ${stringify(fullActual)}`);
31303130
const action = ts.first(refactor.actions);
31313131
assert(action.name === "Move to a new file" && action.description === "Move to a new file");
31323132

3133-
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactor.name, action.name, ts.defaultPreferences)!;
3133+
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.defaultPreferences)!;
31343134
for (const edit of editInfo.edits) {
31353135
const newContent = options.newFileContents[edit.fileName];
31363136
if (newContent === undefined) {
@@ -4836,5 +4836,6 @@ namespace FourSlashInterface {
48364836

48374837
export interface MoveToNewFileOptions {
48384838
readonly newFileContents: { readonly [fileName: string]: string };
4839+
readonly preferences?: ts.UserPreferences;
48394840
}
48404841
}

src/services/codefixes/convertToEs6Module.ts

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ namespace ts.codefix {
33
registerCodeFix({
44
errorCodes: [Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module.code],
55
getCodeActions(context) {
6-
const { sourceFile, program } = context;
6+
const { sourceFile, program, preferences } = context;
77
const changes = textChanges.ChangeTracker.with(context, changes => {
8-
const moduleExportsChangedToDefault = convertFileToEs6Module(sourceFile, program.getTypeChecker(), changes, program.getCompilerOptions().target!);
8+
const moduleExportsChangedToDefault = convertFileToEs6Module(sourceFile, program.getTypeChecker(), changes, program.getCompilerOptions().target!, preferences);
99
if (moduleExportsChangedToDefault) {
1010
for (const importingFile of program.getSourceFiles()) {
11-
fixImportOfModuleExports(importingFile, sourceFile, changes);
11+
fixImportOfModuleExports(importingFile, sourceFile, changes, preferences);
1212
}
1313
}
1414
});
@@ -17,7 +17,7 @@ namespace ts.codefix {
1717
},
1818
});
1919

20-
function fixImportOfModuleExports(importingFile: SourceFile, exportingFile: SourceFile, changes: textChanges.ChangeTracker) {
20+
function fixImportOfModuleExports(importingFile: SourceFile, exportingFile: SourceFile, changes: textChanges.ChangeTracker, preferences: UserPreferences) {
2121
for (const moduleSpecifier of importingFile.imports) {
2222
const imported = getResolvedModule(importingFile, moduleSpecifier.text);
2323
if (!imported || imported.resolvedFileName !== exportingFile.fileName) {
@@ -27,7 +27,7 @@ namespace ts.codefix {
2727
const importNode = importFromModuleSpecifier(moduleSpecifier);
2828
switch (importNode.kind) {
2929
case SyntaxKind.ImportEqualsDeclaration:
30-
changes.replaceNode(importingFile, importNode, makeImport(importNode.name, /*namedImports*/ undefined, moduleSpecifier));
30+
changes.replaceNode(importingFile, importNode, makeImport(importNode.name, /*namedImports*/ undefined, moduleSpecifier, preferences));
3131
break;
3232
case SyntaxKind.CallExpression:
3333
if (isRequireCall(importNode, /*checkArgumentIsStringLiteralLike*/ false)) {
@@ -39,13 +39,13 @@ namespace ts.codefix {
3939
}
4040

4141
/** @returns Whether we converted a `module.exports =` to a default export. */
42-
function convertFileToEs6Module(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, target: ScriptTarget): ModuleExportsChanged {
42+
function convertFileToEs6Module(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, target: ScriptTarget, preferences: UserPreferences): ModuleExportsChanged {
4343
const identifiers: Identifiers = { original: collectFreeIdentifiers(sourceFile), additional: createMap<true>() };
4444
const exports = collectExportRenames(sourceFile, checker, identifiers);
4545
convertExportsAccesses(sourceFile, exports, changes);
4646
let moduleExportsChangedToDefault = false;
4747
for (const statement of sourceFile.statements) {
48-
const moduleExportsChanged = convertStatement(sourceFile, statement, checker, changes, identifiers, target, exports);
48+
const moduleExportsChanged = convertStatement(sourceFile, statement, checker, changes, identifiers, target, exports, preferences);
4949
moduleExportsChangedToDefault = moduleExportsChangedToDefault || moduleExportsChanged;
5050
}
5151
return moduleExportsChangedToDefault;
@@ -98,18 +98,18 @@ namespace ts.codefix {
9898
/** Whether `module.exports =` was changed to `export default` */
9999
type ModuleExportsChanged = boolean;
100100

101-
function convertStatement(sourceFile: SourceFile, statement: Statement, checker: TypeChecker, changes: textChanges.ChangeTracker, identifiers: Identifiers, target: ScriptTarget, exports: ExportRenames): ModuleExportsChanged {
101+
function convertStatement(sourceFile: SourceFile, statement: Statement, checker: TypeChecker, changes: textChanges.ChangeTracker, identifiers: Identifiers, target: ScriptTarget, exports: ExportRenames, preferences: UserPreferences): ModuleExportsChanged {
102102
switch (statement.kind) {
103103
case SyntaxKind.VariableStatement:
104-
convertVariableStatement(sourceFile, statement as VariableStatement, changes, checker, identifiers, target);
104+
convertVariableStatement(sourceFile, statement as VariableStatement, changes, checker, identifiers, target, preferences);
105105
return false;
106106
case SyntaxKind.ExpressionStatement: {
107107
const { expression } = statement as ExpressionStatement;
108108
switch (expression.kind) {
109109
case SyntaxKind.CallExpression: {
110110
if (isRequireCall(expression, /*checkArgumentIsStringLiteralLike*/ true)) {
111111
// For side-effecting require() call, just make a side-effecting import.
112-
changes.replaceNode(sourceFile, statement, makeImport(/*name*/ undefined, /*namedImports*/ undefined, expression.arguments[0]));
112+
changes.replaceNode(sourceFile, statement, makeImport(/*name*/ undefined, /*namedImports*/ undefined, expression.arguments[0], preferences));
113113
}
114114
return false;
115115
}
@@ -125,7 +125,7 @@ namespace ts.codefix {
125125
}
126126
}
127127

128-
function convertVariableStatement(sourceFile: SourceFile, statement: VariableStatement, changes: textChanges.ChangeTracker, checker: TypeChecker, identifiers: Identifiers, target: ScriptTarget): void {
128+
function convertVariableStatement(sourceFile: SourceFile, statement: VariableStatement, changes: textChanges.ChangeTracker, checker: TypeChecker, identifiers: Identifiers, target: ScriptTarget, preferences: UserPreferences): void {
129129
const { declarationList } = statement;
130130
let foundImport = false;
131131
const newNodes = flatMap(declarationList.declarations, decl => {
@@ -138,11 +138,11 @@ namespace ts.codefix {
138138
}
139139
else if (isRequireCall(initializer, /*checkArgumentIsStringLiteralLike*/ true)) {
140140
foundImport = true;
141-
return convertSingleImport(sourceFile, name, initializer.arguments[0], changes, checker, identifiers, target);
141+
return convertSingleImport(sourceFile, name, initializer.arguments[0], changes, checker, identifiers, target, preferences);
142142
}
143143
else if (isPropertyAccessExpression(initializer) && isRequireCall(initializer.expression, /*checkArgumentIsStringLiteralLike*/ true)) {
144144
foundImport = true;
145-
return convertPropertyAccessImport(name, initializer.name.text, initializer.expression.arguments[0], identifiers);
145+
return convertPropertyAccessImport(name, initializer.name.text, initializer.expression.arguments[0], identifiers, preferences);
146146
}
147147
}
148148
// Move it out to its own variable statement. (This will not be used if `!foundImport`)
@@ -155,20 +155,20 @@ namespace ts.codefix {
155155
}
156156

157157
/** Converts `const name = require("moduleSpecifier").propertyName` */
158-
function convertPropertyAccessImport(name: BindingName, propertyName: string, moduleSpecifier: StringLiteralLike, identifiers: Identifiers): ReadonlyArray<Node> {
158+
function convertPropertyAccessImport(name: BindingName, propertyName: string, moduleSpecifier: StringLiteralLike, identifiers: Identifiers, preferences: UserPreferences): ReadonlyArray<Node> {
159159
switch (name.kind) {
160160
case SyntaxKind.ObjectBindingPattern:
161161
case SyntaxKind.ArrayBindingPattern: {
162162
// `const [a, b] = require("c").d` --> `import { d } from "c"; const [a, b] = d;`
163163
const tmp = makeUniqueName(propertyName, identifiers);
164164
return [
165-
makeSingleImport(tmp, propertyName, moduleSpecifier),
165+
makeSingleImport(tmp, propertyName, moduleSpecifier, preferences),
166166
makeConst(/*modifiers*/ undefined, name, createIdentifier(tmp)),
167167
];
168168
}
169169
case SyntaxKind.Identifier:
170170
// `const a = require("b").c` --> `import { c as a } from "./b";
171-
return [makeSingleImport(name.text, propertyName, moduleSpecifier)];
171+
return [makeSingleImport(name.text, propertyName, moduleSpecifier, preferences)];
172172
default:
173173
return Debug.assertNever(name);
174174
}
@@ -340,6 +340,7 @@ namespace ts.codefix {
340340
checker: TypeChecker,
341341
identifiers: Identifiers,
342342
target: ScriptTarget,
343+
preferences: UserPreferences,
343344
): ReadonlyArray<Node> {
344345
switch (name.kind) {
345346
case SyntaxKind.ObjectBindingPattern: {
@@ -348,7 +349,7 @@ namespace ts.codefix {
348349
? undefined
349350
: makeImportSpecifier(e.propertyName && (e.propertyName as Identifier).text, e.name.text)); // tslint:disable-line no-unnecessary-type-assertion (TODO: GH#18217)
350351
if (importSpecifiers) {
351-
return [makeImport(/*name*/ undefined, importSpecifiers, moduleSpecifier)];
352+
return [makeImport(/*name*/ undefined, importSpecifiers, moduleSpecifier, preferences)];
352353
}
353354
}
354355
// falls through -- object destructuring has an interesting pattern and must be a variable declaration
@@ -359,12 +360,12 @@ namespace ts.codefix {
359360
*/
360361
const tmp = makeUniqueName(moduleSpecifierToValidIdentifier(moduleSpecifier.text, target), identifiers);
361362
return [
362-
makeImport(createIdentifier(tmp), /*namedImports*/ undefined, moduleSpecifier),
363+
makeImport(createIdentifier(tmp), /*namedImports*/ undefined, moduleSpecifier, preferences),
363364
makeConst(/*modifiers*/ undefined, getSynthesizedDeepClone(name), createIdentifier(tmp)),
364365
];
365366
}
366367
case SyntaxKind.Identifier:
367-
return convertSingleIdentifierImport(file, name, moduleSpecifier, changes, checker, identifiers);
368+
return convertSingleIdentifierImport(file, name, moduleSpecifier, changes, checker, identifiers, preferences);
368369
default:
369370
return Debug.assertNever(name);
370371
}
@@ -374,7 +375,7 @@ namespace ts.codefix {
374375
* Convert `import x = require("x").`
375376
* Also converts uses like `x.y()` to `y()` and uses a named import.
376377
*/
377-
function convertSingleIdentifierImport(file: SourceFile, name: Identifier, moduleSpecifier: StringLiteralLike, changes: textChanges.ChangeTracker, checker: TypeChecker, identifiers: Identifiers): ReadonlyArray<Node> {
378+
function convertSingleIdentifierImport(file: SourceFile, name: Identifier, moduleSpecifier: StringLiteralLike, changes: textChanges.ChangeTracker, checker: TypeChecker, identifiers: Identifiers, preferences: UserPreferences): ReadonlyArray<Node> {
378379
const nameSymbol = checker.getSymbolAtLocation(name);
379380
// Maps from module property name to name actually used. (The same if there isn't shadowing.)
380381
const namedBindingsNames = createMap<string>();
@@ -409,7 +410,7 @@ namespace ts.codefix {
409410
// If it was unused, ensure that we at least import *something*.
410411
needDefaultImport = true;
411412
}
412-
return [makeImport(needDefaultImport ? getSynthesizedDeepClone(name) : undefined, namedBindings, moduleSpecifier)];
413+
return [makeImport(needDefaultImport ? getSynthesizedDeepClone(name) : undefined, namedBindings, moduleSpecifier, preferences)];
413414
}
414415

415416
// Identifiers helpers
@@ -481,10 +482,10 @@ namespace ts.codefix {
481482
getSynthesizedDeepClones(cls.members));
482483
}
483484

484-
function makeSingleImport(localName: string, propertyName: string, moduleSpecifier: StringLiteralLike): ImportDeclaration {
485+
function makeSingleImport(localName: string, propertyName: string, moduleSpecifier: StringLiteralLike, preferences: UserPreferences): ImportDeclaration {
485486
return propertyName === "default"
486-
? makeImport(createIdentifier(localName), /*namedImports*/ undefined, moduleSpecifier)
487-
: makeImport(/*name*/ undefined, [makeImportSpecifier(propertyName, localName)], moduleSpecifier);
487+
? makeImport(createIdentifier(localName), /*namedImports*/ undefined, moduleSpecifier, preferences)
488+
: makeImport(/*name*/ undefined, [makeImportSpecifier(propertyName, localName)], moduleSpecifier, preferences);
488489
}
489490

490491
function makeImportSpecifier(propertyName: string | undefined, name: string): ImportSpecifier {

src/services/codefixes/fixInvalidImportSyntax.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace ts.codefix {
2828
const variations: CodeFixAction[] = [];
2929

3030
// import Bluebird from "bluebird";
31-
variations.push(createAction(context, sourceFile, node, makeImport(namespace.name, /*namedImports*/ undefined, node.moduleSpecifier)));
31+
variations.push(createAction(context, sourceFile, node, makeImport(namespace.name, /*namedImports*/ undefined, node.moduleSpecifier, context.preferences)));
3232

3333
if (getEmitModuleKind(opts) === ModuleKind.CommonJS) {
3434
// import Bluebird = require("bluebird");

src/services/codefixes/useDefaultImport.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ namespace ts.codefix {
88
const { sourceFile, span: { start } } = context;
99
const info = getInfo(sourceFile, start);
1010
if (!info) return undefined;
11-
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info));
11+
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info, context.preferences));
1212
return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_default_import, fixId, Diagnostics.Convert_all_to_default_imports)];
1313
},
1414
fixIds: [fixId],
1515
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
1616
const info = getInfo(diag.file, diag.start);
17-
if (info) doChange(changes, diag.file, info);
17+
if (info) doChange(changes, diag.file, info, context.preferences);
1818
}),
1919
});
2020

@@ -36,7 +36,7 @@ namespace ts.codefix {
3636
}
3737
}
3838

39-
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info): void {
40-
changes.replaceNode(sourceFile, info.importNode, makeImport(info.name, /*namedImports*/ undefined, info.moduleSpecifier));
39+
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info, preferences: UserPreferences): void {
40+
changes.replaceNode(sourceFile, info.importNode, makeImport(info.name, /*namedImports*/ undefined, info.moduleSpecifier, preferences));
4141
}
4242
}

0 commit comments

Comments
 (0)