Merge branch 'master' into esau-squash

# Conflicts:
#	tests/baselines/reference/api/typescript.d.ts
This commit is contained in:
Ryan Cavanaugh
2018-06-15 10:40:46 -07:00
20 changed files with 331 additions and 308 deletions

View File

@@ -194,7 +194,6 @@ namespace ts.codefix {
function getCodeActionForNewImport(context: SymbolContext & { preferences: UserPreferences }, { moduleSpecifier, importKind }: NewImportInfo): CodeFixAction {
const { sourceFile, symbolName, preferences } = context;
const lastImportDeclaration = findLast(sourceFile.statements, isAnyImportSyntax);
const moduleSpecifierWithoutQuotes = stripQuotes(moduleSpecifier);
const quotedModuleSpecifier = makeStringLiteral(moduleSpecifierWithoutQuotes, getQuotePreference(sourceFile, preferences));
@@ -210,14 +209,7 @@ namespace ts.codefix {
createIdentifier(symbolName),
createExternalModuleReference(quotedModuleSpecifier));
const changes = ChangeTracker.with(context, changeTracker => {
if (lastImportDeclaration) {
changeTracker.insertNodeAfter(sourceFile, lastImportDeclaration, importDecl);
}
else {
changeTracker.insertNodeAtTopOfFile(sourceFile, importDecl, /*blankLineBetween*/ true);
}
});
const changes = ChangeTracker.with(context, t => insertImport(t, sourceFile, importDecl));
// if this file doesn't have any import statements, insert an import statement and then insert a new line
// between the only import statement and user code. Otherwise just insert the statement because chances

View File

@@ -103,13 +103,16 @@ namespace ts {
preferences: UserPreferences,
): void {
for (const sourceFile of program.getSourceFiles()) {
const newImportFromPath = oldToNew(sourceFile.fileName) || sourceFile.fileName;
const newFromOld = oldToNew(sourceFile.fileName);
const newImportFromPath = newFromOld !== undefined ? newFromOld : sourceFile.fileName;
const newImportFromDirectory = getDirectoryPath(newImportFromPath);
const oldFromNew: string | undefined = newToOld(sourceFile.fileName);
const oldImportFromPath: string = oldFromNew || sourceFile.fileName;
const oldImportFromDirectory = getDirectoryPath(oldImportFromPath);
const importingSourceFileMoved = newFromOld !== undefined || oldFromNew !== undefined;
updateImportsWorker(sourceFile, changeTracker,
referenceText => {
if (!pathIsRelative(referenceText)) return undefined;
@@ -123,7 +126,10 @@ namespace ts {
// TODO:GH#18217
? getSourceFileToImportFromResolved(resolveModuleName(importLiteral.text, oldImportFromPath, program.getCompilerOptions(), host as ModuleResolutionHost), oldToNew, program)
: getSourceFileToImport(importLiteral, sourceFile, program, host, oldToNew);
return toImport === undefined ? undefined : moduleSpecifiers.getModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport, host, preferences);
// If neither the importing source file nor the imported file moved, do nothing.
return toImport === undefined || !toImport.updated && !importingSourceFileMoved
? undefined
: moduleSpecifiers.getModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport.newFileName, host, preferences);
});
}
}
@@ -135,12 +141,18 @@ namespace ts {
return ensurePathIsNonModuleName(combineNormal(pathA, pathB));
}
function getSourceFileToImport(importLiteral: StringLiteralLike, importingSourceFile: SourceFile, program: Program, host: LanguageServiceHost, oldToNew: PathUpdater): string | undefined {
interface ToImport {
readonly newFileName: string;
/** True if the imported file was renamed. */
readonly updated: boolean;
}
function getSourceFileToImport(importLiteral: StringLiteralLike, importingSourceFile: SourceFile, program: Program, host: LanguageServiceHost, oldToNew: PathUpdater): ToImport | undefined {
const symbol = program.getTypeChecker().getSymbolAtLocation(importLiteral);
if (symbol) {
if (symbol.declarations.some(d => isAmbientModule(d))) return undefined; // No need to update if it's an ambient module
const oldFileName = find(symbol.declarations, isSourceFile)!.fileName;
return oldToNew(oldFileName) || oldFileName;
const newFileName = oldToNew(oldFileName);
return newFileName === undefined ? { newFileName: oldFileName, updated: false } : { newFileName, updated: true };
}
else {
const resolved = host.resolveModuleNames
@@ -150,14 +162,15 @@ namespace ts {
}
}
function getSourceFileToImportFromResolved(resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater, program: Program): string | undefined {
function getSourceFileToImportFromResolved(resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater, program: Program): ToImport | undefined {
return resolved && (
(resolved.resolvedModule && getIfInProgram(resolved.resolvedModule.resolvedFileName)) || firstDefined(resolved.failedLookupLocations, getIfInProgram));
function getIfInProgram(oldLocation: string): string | undefined {
function getIfInProgram(oldLocation: string): ToImport | undefined {
const newLocation = oldToNew(oldLocation);
return program.getSourceFile(oldLocation) || newLocation !== undefined && program.getSourceFile(newLocation)
? newLocation || oldLocation
? newLocation !== undefined ? { newFileName: newLocation, updated: true } : { newFileName: oldLocation, updated: false }
: undefined;
}
}

View File

@@ -121,7 +121,7 @@ namespace ts.refactor {
const quotePreference = getQuotePreference(oldFile, preferences);
const importsFromNewFile = createOldFileImportsFromNewFile(usage.oldFileImportsFromNewFile, newModuleName, useEs6ModuleSyntax, quotePreference);
if (importsFromNewFile) {
changes.insertNodeBefore(oldFile, oldFile.statements[0], importsFromNewFile, /*blankLineBetween*/ true);
insertImport(changes, oldFile, importsFromNewFile);
}
deleteUnusedOldImports(oldFile, toMove.all, changes, usage.unusedImportsFromOldFile, checker);

View File

@@ -1379,6 +1379,17 @@ namespace ts {
return textSpanContainsPosition(span, node.getStart(file)) &&
node.getEnd() <= textSpanEnd(span);
}
/* @internal */
export function insertImport(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importDecl: Statement): void {
const lastImportDeclaration = findLast(sourceFile.statements, isAnyImportSyntax);
if (lastImportDeclaration) {
changes.insertNodeAfter(sourceFile, lastImportDeclaration, importDecl);
}
else {
changes.insertNodeAtTopOfFile(sourceFile, importDecl, /*blankLineBetween*/ true);
}
}
}
// Display-part writer helpers