From 22e2a3d6e63bae7b9a74281509c1b60ad5a5914d Mon Sep 17 00:00:00 2001 From: hjonasson Date: Wed, 3 Dec 2025 15:59:15 +1300 Subject: [PATCH 1/4] Rename mock and require file references --- src/compiler/types.ts | 7 + src/services/getEditsForFileRename.ts | 149 +++++++++++++++++- tests/baselines/reference/api/typescript.d.ts | 7 + .../getEditsForFileRename_dynamicImport.ts | 20 +++ .../getEditsForFileRename_jestMock.ts | 23 +++ .../getEditsForFileRename_requireInTs.ts | 18 +++ 6 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 tests/cases/fourslash/getEditsForFileRename_dynamicImport.ts create mode 100644 tests/cases/fourslash/getEditsForFileRename_jestMock.ts create mode 100644 tests/cases/fourslash/getEditsForFileRename_requireInTs.ts diff --git a/src/compiler/types.ts b/src/compiler/types.ts index cdba2e880afc3..77c66574093de 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -10564,6 +10564,13 @@ export interface UserPreferences { * Default: `500` */ readonly maximumHoverLength?: number; + /** + * If enabled, file rename operations will update string literals in test framework + * mocking functions such as jest.mock(), vitest.mock(), etc. + * + * Default: false + */ + readonly updateImportsInTestFrameworkCalls?: boolean; } export type OrganizeImportsTypeOrder = "last" | "inline" | "first"; diff --git a/src/services/getEditsForFileRename.ts b/src/services/getEditsForFileRename.ts index cffc15aeeabb3..64b51149beeea 100644 --- a/src/services/getEditsForFileRename.ts +++ b/src/services/getEditsForFileRename.ts @@ -1,4 +1,5 @@ import { + CallExpression, combinePaths, createGetCanonicalFileName, createModuleSpecifierResolutionHost, @@ -11,6 +12,7 @@ import { factory, FileTextChanges, find, + forEachChild, forEach, formatting, GetCanonicalFileName, @@ -24,15 +26,22 @@ import { hostUsesCaseSensitiveFileNames, isAmbientModule, isArrayLiteralExpression, + isCallExpression, + isIdentifier, + isImportCall, isObjectLiteralExpression, + isPropertyAccessExpression, isPropertyAssignment, + isRequireCall, isSourceFile, isStringLiteral, + isStringLiteralLike, LanguageServiceHost, last, mapDefined, ModuleResolutionHost, moduleSpecifiers, + Node, normalizePath, pathIsRelative, Program, @@ -66,7 +75,7 @@ export function getEditsForFileRename( const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName, sourceMapper); return textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => { updateTsconfigFiles(program, changeTracker, oldToNew, oldFileOrDirPath, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames); - updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName); + updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName, preferences); }); } @@ -101,6 +110,96 @@ function makeCorrespondingRelativeChange(a0: string, b0: string, a1: string, get return combinePathsSafe(getDirectoryPath(a1), rel); } +/** + * Configuration for test framework function patterns that should be updated during file renames. + */ +interface TestFrameworkPattern { + /** Object name (e.g., "jest", "vitest") */ + readonly object: string; + /** Method name (e.g., "mock", "requireActual") */ + readonly method: string; + /** 0-based index of the argument that contains the module path */ + readonly pathArgumentIndex: number; +} + +/** + * List of test framework patterns to recognize. + * Extensible design - add new patterns here. + */ +const testFrameworkPatterns: readonly TestFrameworkPattern[] = [ + // Jest patterns + { object: "jest", method: "mock", pathArgumentIndex: 0 }, + { object: "jest", method: "unmock", pathArgumentIndex: 0 }, + { object: "jest", method: "requireActual", pathArgumentIndex: 0 }, + { object: "jest", method: "requireMock", pathArgumentIndex: 0 }, + { object: "jest", method: "doMock", pathArgumentIndex: 0 }, + { object: "jest", method: "dontMock", pathArgumentIndex: 0 }, + + // Vitest patterns + { object: "vitest", method: "mock", pathArgumentIndex: 0 }, + { object: "vi", method: "mock", pathArgumentIndex: 0 }, +]; + +/** + * Checks if a call expression is a module loading pattern that should be updated. + * Returns the string literal argument if it matches, undefined otherwise. + */ +function getModulePathArgument( + node: CallExpression, + preferences: UserPreferences, +): StringLiteralLike | undefined { + // Check for dynamic import: import("./module") + if (isImportCall(node)) { + const arg = node.arguments[0]; + if (arg && isStringLiteralLike(arg)) { + return arg; + } + return undefined; + } + + // Check for require: require("./module") + if (isRequireCall(node, /*requireStringLiteralLikeArgument*/ true)) { + return node.arguments[0]; + } + + // Check for test framework patterns (opt-in only) + if (preferences.updateImportsInTestFrameworkCalls) { + // Must have form: object.method(...) + if (!isPropertyAccessExpression(node.expression)) { + return undefined; + } + + const propertyAccess = node.expression; + + // Check if it's a simple identifier (not a nested property access) + if (!isIdentifier(propertyAccess.expression)) { + return undefined; + } + + const objectName = propertyAccess.expression.text; + const methodName = propertyAccess.name.text; + + // Find matching pattern + const pattern = find(testFrameworkPatterns, p => + p.object === objectName && p.method === methodName + ); + + if (!pattern) { + return undefined; + } + + // Get the argument at the specified index + const arg = node.arguments[pattern.pathArgumentIndex]; + + // Only handle string literals, not template literals with substitutions + if (arg && isStringLiteral(arg)) { + return arg; + } + } + + return undefined; +} + function updateTsconfigFiles(program: Program, changeTracker: textChanges.ChangeTracker, oldToNew: PathUpdater, oldFileOrDirPath: string, newFileOrDirPath: string, currentDirectory: string, useCaseSensitiveFileNames: boolean): void { const { configFile } = program.getCompilerOptions(); if (!configFile) return; @@ -181,6 +280,7 @@ function updateImports( newToOld: PathUpdater, host: LanguageServiceHost, getCanonicalFileName: GetCanonicalFileName, + preferences: UserPreferences, ): void { const allFiles = program.getSourceFiles(); for (const sourceFile of allFiles) { @@ -214,7 +314,7 @@ function updateImports( return toImport !== undefined && (toImport.updated || (importingSourceFileMoved && pathIsRelative(importLiteral.text))) ? moduleSpecifiers.updateModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport.newFileName, createModuleSpecifierResolutionHost(program, host), importLiteral.text) : undefined; - }); + }, preferences); } } @@ -290,7 +390,7 @@ function getSourceFileToImportFromResolved(importLiteral: StringLiteralLike, res } } -function updateImportsWorker(sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateRef: (refText: string) => string | undefined, updateImport: (importLiteral: StringLiteralLike) => string | undefined) { +function updateImportsWorker(sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateRef: (refText: string) => string | undefined, updateImport: (importLiteral: StringLiteralLike) => string | undefined, preferences: UserPreferences) { for (const ref of sourceFile.referencedFiles || emptyArray) { // TODO: GH#26162 const updated = updateRef(ref.fileName); if (updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end)) changeTracker.replaceRangeWithText(sourceFile, ref, updated); @@ -300,6 +400,49 @@ function updateImportsWorker(sourceFile: SourceFile, changeTracker: textChanges. const updated = updateImport(importStringLiteral); if (updated !== undefined && updated !== importStringLiteral.text) changeTracker.replaceRangeWithText(sourceFile, createStringRange(importStringLiteral, sourceFile), updated); } + + // Update additional module loading patterns (dynamic import, require, test mocks) + // This catches patterns that aren't in sourceFile.imports (like require in .ts files) + updateModuleLoadingCalls(sourceFile, changeTracker, updateImport, preferences); +} + +/** + * Updates module loading calls (dynamic import, require, test framework mocks) in a source file. + * Handles import(), require(), jest.mock(), vitest.mock(), etc. + */ +function updateModuleLoadingCalls( + sourceFile: SourceFile, + changeTracker: textChanges.ChangeTracker, + updateImport: (importLiteral: StringLiteralLike) => string | undefined, + preferences: UserPreferences, +): void { + // Create a set of string literals already processed from sourceFile.imports to avoid duplicates + const processedImports = new Set(sourceFile.imports); + + // Visitor pattern - recursively walk the AST + function visitor(node: Node): void { + // Check for call expressions + if (isCallExpression(node)) { + const pathArgument = getModulePathArgument(node, preferences); + // Skip if this path argument was already processed from sourceFile.imports + if (pathArgument && !processedImports.has(pathArgument)) { + const updated = updateImport(pathArgument); + if (updated !== undefined && updated !== pathArgument.text) { + changeTracker.replaceRangeWithText( + sourceFile, + createStringRange(pathArgument, sourceFile), + updated + ); + } + } + } + + // Continue walking the tree + forEachChild(node, visitor); + } + + // Start the traversal + visitor(sourceFile); } function createStringRange(node: StringLiteralLike, sourceFile: SourceFileLike): TextRange { diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index ba6404355b3c3..9895ad0cbd441 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -8430,6 +8430,13 @@ declare namespace ts { * Default: `500` */ readonly maximumHoverLength?: number; + /** + * If enabled, file rename operations will update string literals in test framework + * mocking functions such as jest.mock(), vitest.mock(), etc. + * + * Default: `false` + */ + readonly updateImportsInTestFrameworkCalls?: boolean; } type OrganizeImportsTypeOrder = "last" | "inline" | "first"; /** Represents a bigint literal value without requiring bigint support */ diff --git a/tests/cases/fourslash/getEditsForFileRename_dynamicImport.ts b/tests/cases/fourslash/getEditsForFileRename_dynamicImport.ts new file mode 100644 index 0000000000000..2ca96188d3e0f --- /dev/null +++ b/tests/cases/fourslash/getEditsForFileRename_dynamicImport.ts @@ -0,0 +1,20 @@ +/// + +// @Filename: /src/old.ts +////export const value = 1; + +// @Filename: /src/test.ts +////import("./old"); +////const x = import("./old"); +////import { value } from "./old"; + +verify.getEditsForFileRename({ + oldPath: "/src/old.ts", + newPath: "/src/new.ts", + newFileContents: { + "/src/test.ts": +`import("./new"); +const x = import("./new"); +import { value } from "./new";`, + }, +}); diff --git a/tests/cases/fourslash/getEditsForFileRename_jestMock.ts b/tests/cases/fourslash/getEditsForFileRename_jestMock.ts new file mode 100644 index 0000000000000..6e9ee6f2ba38d --- /dev/null +++ b/tests/cases/fourslash/getEditsForFileRename_jestMock.ts @@ -0,0 +1,23 @@ +/// + +// @Filename: /src/utils/old.ts +////export const helper = () => 42; + +// @Filename: /src/utils/__tests__/helper.test.ts +////jest.mock("../old"); +////jest.requireActual("../old"); +////import { helper } from "../old"; + +verify.getEditsForFileRename({ + oldPath: "/src/utils/old.ts", + newPath: "/src/utils/new.ts", + newFileContents: { + "/src/utils/__tests__/helper.test.ts": +`jest.mock("../new"); +jest.requireActual("../new"); +import { helper } from "../new";`, + }, + preferences: { + updateImportsInTestFrameworkCalls: true, + }, +}); diff --git a/tests/cases/fourslash/getEditsForFileRename_requireInTs.ts b/tests/cases/fourslash/getEditsForFileRename_requireInTs.ts new file mode 100644 index 0000000000000..4fbda1f8edac5 --- /dev/null +++ b/tests/cases/fourslash/getEditsForFileRename_requireInTs.ts @@ -0,0 +1,18 @@ +/// + +// @Filename: /src/old.ts +////export const value = 1; + +// @Filename: /src/test.ts +////const old = require("./old"); +////import { value } from "./old"; + +verify.getEditsForFileRename({ + oldPath: "/src/old.ts", + newPath: "/src/new.ts", + newFileContents: { + "/src/test.ts": +`const old = require("./new"); +import { value } from "./new";`, + }, +}); From 601ee9477cb457b1a8cac587a8ceedd19ef15906 Mon Sep 17 00:00:00 2001 From: hjonasson Date: Thu, 4 Dec 2025 13:20:32 +1300 Subject: [PATCH 2/4] Formatting issues --- src/services/getEditsForFileRename.ts | 432 ++++++++++++++++++++------ 1 file changed, 338 insertions(+), 94 deletions(-) diff --git a/src/services/getEditsForFileRename.ts b/src/services/getEditsForFileRename.ts index 64b51149beeea..7b35bed2e2b5c 100644 --- a/src/services/getEditsForFileRename.ts +++ b/src/services/getEditsForFileRename.ts @@ -12,8 +12,8 @@ import { factory, FileTextChanges, find, - forEachChild, forEach, + forEachChild, formatting, GetCanonicalFileName, getDirectoryPath, @@ -67,16 +67,47 @@ export function getEditsForFileRename( host: LanguageServiceHost, formatContext: formatting.FormatContext, preferences: UserPreferences, - sourceMapper: SourceMapper, + sourceMapper: SourceMapper ): readonly FileTextChanges[] { const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host); - const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames); - const oldToNew = getPathUpdater(oldFileOrDirPath, newFileOrDirPath, getCanonicalFileName, sourceMapper); - const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName, sourceMapper); - return textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => { - updateTsconfigFiles(program, changeTracker, oldToNew, oldFileOrDirPath, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames); - updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName, preferences); - }); + const getCanonicalFileName = createGetCanonicalFileName( + useCaseSensitiveFileNames + ); + const oldToNew = getPathUpdater( + oldFileOrDirPath, + newFileOrDirPath, + getCanonicalFileName, + sourceMapper + ); + const newToOld = getPathUpdater( + newFileOrDirPath, + oldFileOrDirPath, + getCanonicalFileName, + sourceMapper + ); + return textChanges.ChangeTracker.with( + { host, formatContext, preferences }, + (changeTracker) => { + updateTsconfigFiles( + program, + changeTracker, + oldToNew, + oldFileOrDirPath, + newFileOrDirPath, + host.getCurrentDirectory(), + useCaseSensitiveFileNames + ); + updateImports( + program, + changeTracker, + oldToNew, + newToOld, + host, + getCanonicalFileName, + preferences + ); + } + ); } /** @@ -87,25 +118,53 @@ export function getEditsForFileRename( export type PathUpdater = (path: string) => string | undefined; // exported for tests /** @internal */ -export function getPathUpdater(oldFileOrDirPath: string, newFileOrDirPath: string, getCanonicalFileName: GetCanonicalFileName, sourceMapper: SourceMapper | undefined): PathUpdater { +export function getPathUpdater( + oldFileOrDirPath: string, + newFileOrDirPath: string, + getCanonicalFileName: GetCanonicalFileName, + sourceMapper: SourceMapper | undefined +): PathUpdater { const canonicalOldPath = getCanonicalFileName(oldFileOrDirPath); - return path => { - const originalPath = sourceMapper && sourceMapper.tryGetSourcePosition({ fileName: path, pos: 0 }); - const updatedPath = getUpdatedPath(originalPath ? originalPath.fileName : path); + return (path) => { + const originalPath = + sourceMapper && + sourceMapper.tryGetSourcePosition({ fileName: path, pos: 0 }); + const updatedPath = getUpdatedPath( + originalPath ? originalPath.fileName : path + ); return originalPath - ? updatedPath === undefined ? undefined : makeCorrespondingRelativeChange(originalPath.fileName, updatedPath, path, getCanonicalFileName) + ? updatedPath === undefined + ? undefined + : makeCorrespondingRelativeChange( + originalPath.fileName, + updatedPath, + path, + getCanonicalFileName + ) : updatedPath; }; function getUpdatedPath(pathToUpdate: string): string | undefined { - if (getCanonicalFileName(pathToUpdate) === canonicalOldPath) return newFileOrDirPath; - const suffix = tryRemoveDirectoryPrefix(pathToUpdate, canonicalOldPath, getCanonicalFileName); - return suffix === undefined ? undefined : newFileOrDirPath + "/" + suffix; + if (getCanonicalFileName(pathToUpdate) === canonicalOldPath) + return newFileOrDirPath; + const suffix = tryRemoveDirectoryPrefix( + pathToUpdate, + canonicalOldPath, + getCanonicalFileName + ); + return suffix === undefined + ? undefined + : newFileOrDirPath + "/" + suffix; } } // Relative path from a0 to b0 should be same as relative path from a1 to b1. Returns b1. -function makeCorrespondingRelativeChange(a0: string, b0: string, a1: string, getCanonicalFileName: GetCanonicalFileName): string { +function makeCorrespondingRelativeChange( + a0: string, + b0: string, + a1: string, + getCanonicalFileName: GetCanonicalFileName +): string { const rel = getRelativePathFromFile(a0, b0, getCanonicalFileName); return combinePathsSafe(getDirectoryPath(a1), rel); } @@ -146,7 +205,7 @@ const testFrameworkPatterns: readonly TestFrameworkPattern[] = [ */ function getModulePathArgument( node: CallExpression, - preferences: UserPreferences, + preferences: UserPreferences ): StringLiteralLike | undefined { // Check for dynamic import: import("./module") if (isImportCall(node)) { @@ -180,8 +239,9 @@ function getModulePathArgument( const methodName = propertyAccess.name.text; // Find matching pattern - const pattern = find(testFrameworkPatterns, p => - p.object === objectName && p.method === methodName + const pattern = find( + testFrameworkPatterns, + (p) => p.object === objectName && p.method === methodName ); if (!pattern) { @@ -200,7 +260,15 @@ function getModulePathArgument( return undefined; } -function updateTsconfigFiles(program: Program, changeTracker: textChanges.ChangeTracker, oldToNew: PathUpdater, oldFileOrDirPath: string, newFileOrDirPath: string, currentDirectory: string, useCaseSensitiveFileNames: boolean): void { +function updateTsconfigFiles( + program: Program, + changeTracker: textChanges.ChangeTracker, + oldToNew: PathUpdater, + oldFileOrDirPath: string, + newFileOrDirPath: string, + currentDirectory: string, + useCaseSensitiveFileNames: boolean +): void { const { configFile } = program.getCompilerOptions(); if (!configFile) return; const configDir = getDirectoryPath(configFile.fileName); @@ -214,41 +282,85 @@ function updateTsconfigFiles(program: Program, changeTracker: textChanges.Change case "include": case "exclude": { const foundExactMatch = updatePaths(property); - if (foundExactMatch || propertyName !== "include" || !isArrayLiteralExpression(property.initializer)) return; - const includes = mapDefined(property.initializer.elements, e => isStringLiteral(e) ? e.text : undefined); + if ( + foundExactMatch || + propertyName !== "include" || + !isArrayLiteralExpression(property.initializer) + ) + return; + const includes = mapDefined( + property.initializer.elements, + (e) => (isStringLiteral(e) ? e.text : undefined) + ); if (includes.length === 0) return; - const matchers = getFileMatcherPatterns(configDir, /*excludes*/ [], includes, useCaseSensitiveFileNames, currentDirectory); + const matchers = getFileMatcherPatterns( + configDir, + /*excludes*/ [], + includes, + useCaseSensitiveFileNames, + currentDirectory + ); // If there isn't some include for this, add a new one. if ( - getRegexFromPattern(Debug.checkDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(oldFileOrDirPath) && - !getRegexFromPattern(Debug.checkDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(newFileOrDirPath) + getRegexFromPattern( + Debug.checkDefined(matchers.includeFilePattern), + useCaseSensitiveFileNames + ).test(oldFileOrDirPath) && + !getRegexFromPattern( + Debug.checkDefined(matchers.includeFilePattern), + useCaseSensitiveFileNames + ).test(newFileOrDirPath) ) { - changeTracker.insertNodeAfter(configFile, last(property.initializer.elements), factory.createStringLiteral(relativePath(newFileOrDirPath))); + changeTracker.insertNodeAfter( + configFile, + last(property.initializer.elements), + factory.createStringLiteral( + relativePath(newFileOrDirPath) + ) + ); } return; } case "compilerOptions": - forEachProperty(property.initializer, (property, propertyName) => { - const option = getOptionFromName(propertyName); - Debug.assert(option?.type !== "listOrElement"); - if (option && (option.isFilePath || option.type === "list" && option.element.isFilePath)) { - updatePaths(property); + forEachProperty( + property.initializer, + (property, propertyName) => { + const option = getOptionFromName(propertyName); + Debug.assert(option?.type !== "listOrElement"); + if ( + option && + (option.isFilePath || + (option.type === "list" && + option.element.isFilePath)) + ) { + updatePaths(property); + } else if (propertyName === "paths") { + forEachProperty( + property.initializer, + (pathsProperty) => { + if ( + !isArrayLiteralExpression( + pathsProperty.initializer + ) + ) + return; + for (const e of pathsProperty.initializer + .elements) { + tryUpdateString(e); + } + } + ); + } } - else if (propertyName === "paths") { - forEachProperty(property.initializer, pathsProperty => { - if (!isArrayLiteralExpression(pathsProperty.initializer)) return; - for (const e of pathsProperty.initializer.elements) { - tryUpdateString(e); - } - }); - } - }); + ); return; } }); function updatePaths(property: PropertyAssignment): boolean { - const elements = isArrayLiteralExpression(property.initializer) ? property.initializer.elements : [property.initializer]; + const elements = isArrayLiteralExpression(property.initializer) + ? property.initializer.elements + : [property.initializer]; let foundExactMatch = false; for (const element of elements) { foundExactMatch = tryUpdateString(element) || foundExactMatch; @@ -262,14 +374,22 @@ function updateTsconfigFiles(program: Program, changeTracker: textChanges.Change const updated = oldToNew(elementFileName); if (updated !== undefined) { - changeTracker.replaceRangeWithText(configFile!, createStringRange(element, configFile!), relativePath(updated)); + changeTracker.replaceRangeWithText( + configFile!, + createStringRange(element, configFile!), + relativePath(updated) + ); return true; } return false; } function relativePath(path: string): string { - return getRelativePathFromDirectory(configDir, path, /*ignoreCase*/ !useCaseSensitiveFileNames); + return getRelativePathFromDirectory( + configDir, + path, + /*ignoreCase*/ !useCaseSensitiveFileNames + ); } } @@ -280,7 +400,7 @@ function updateImports( newToOld: PathUpdater, host: LanguageServiceHost, getCanonicalFileName: GetCanonicalFileName, - preferences: UserPreferences, + preferences: UserPreferences ): void { const allFiles = program.getSourceFiles(); for (const sourceFile of allFiles) { @@ -292,29 +412,83 @@ function updateImports( 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; - const oldAbsolute = combinePathsSafe(oldImportFromDirectory, referenceText); - const newAbsolute = oldToNew(oldAbsolute); - return newAbsolute === undefined ? undefined : ensurePathIsNonModuleName(getRelativePathFromDirectory(newImportFromDirectory, newAbsolute, getCanonicalFileName)); - }, importLiteral => { - const importedModuleSymbol = program.getTypeChecker().getSymbolAtLocation(importLiteral); - // No need to update if it's an ambient module^M - if (importedModuleSymbol?.declarations && importedModuleSymbol.declarations.some(d => isAmbientModule(d))) return undefined; - - const toImport = oldFromNew !== undefined - // If we're at the new location (file was already renamed), need to redo module resolution starting from the old location. - // TODO:GH#18217 - ? getSourceFileToImportFromResolved(importLiteral, resolveModuleName(importLiteral.text, oldImportFromPath, program.getCompilerOptions(), host as ModuleResolutionHost), oldToNew, allFiles) - : getSourceFileToImport(importedModuleSymbol, importLiteral, sourceFile, program, host, oldToNew); - - // Need an update if the imported file moved, or the importing file moved and was using a relative path. - return toImport !== undefined && (toImport.updated || (importingSourceFileMoved && pathIsRelative(importLiteral.text))) - ? moduleSpecifiers.updateModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport.newFileName, createModuleSpecifierResolutionHost(program, host), importLiteral.text) - : undefined; - }, preferences); + const importingSourceFileMoved = + newFromOld !== undefined || oldFromNew !== undefined; + + updateImportsWorker( + sourceFile, + changeTracker, + (referenceText) => { + if (!pathIsRelative(referenceText)) return undefined; + const oldAbsolute = combinePathsSafe( + oldImportFromDirectory, + referenceText + ); + const newAbsolute = oldToNew(oldAbsolute); + return newAbsolute === undefined + ? undefined + : ensurePathIsNonModuleName( + getRelativePathFromDirectory( + newImportFromDirectory, + newAbsolute, + getCanonicalFileName + ) + ); + }, + (importLiteral) => { + const importedModuleSymbol = program + .getTypeChecker() + .getSymbolAtLocation(importLiteral); + // No need to update if it's an ambient module^M + if ( + importedModuleSymbol?.declarations && + importedModuleSymbol.declarations.some((d) => + isAmbientModule(d) + ) + ) + return undefined; + + const toImport = + oldFromNew !== undefined + ? // If we're at the new location (file was already renamed), need to redo module resolution starting from the old location. + // TODO:GH#18217 + getSourceFileToImportFromResolved( + importLiteral, + resolveModuleName( + importLiteral.text, + oldImportFromPath, + program.getCompilerOptions(), + host as ModuleResolutionHost + ), + oldToNew, + allFiles + ) + : getSourceFileToImport( + importedModuleSymbol, + importLiteral, + sourceFile, + program, + host, + oldToNew + ); + + // Need an update if the imported file moved, or the importing file moved and was using a relative path. + return toImport !== undefined && + (toImport.updated || + (importingSourceFileMoved && + pathIsRelative(importLiteral.text))) + ? moduleSpecifiers.updateModuleSpecifier( + program.getCompilerOptions(), + sourceFile, + newImportFromPath, + toImport.newFileName, + createModuleSpecifierResolutionHost(program, host), + importLiteral.text + ) + : undefined; + }, + preferences + ); } } @@ -336,24 +510,50 @@ function getSourceFileToImport( importingSourceFile: SourceFile, program: Program, host: LanguageServiceHost, - oldToNew: PathUpdater, + oldToNew: PathUpdater ): ToImport | undefined { if (importedModuleSymbol) { // `find` should succeed because we checked for ambient modules before calling this function. - const oldFileName = find(importedModuleSymbol.declarations, isSourceFile)!.fileName; + const oldFileName = find( + importedModuleSymbol.declarations, + isSourceFile + )!.fileName; const newFileName = oldToNew(oldFileName); - return newFileName === undefined ? { newFileName: oldFileName, updated: false } : { newFileName, updated: true }; - } - else { - const mode = program.getModeForUsageLocation(importingSourceFile, importLiteral); - const resolved = host.resolveModuleNameLiterals || !host.resolveModuleNames ? - program.getResolvedModuleFromModuleSpecifier(importLiteral, importingSourceFile) : - host.getResolvedModuleWithFailedLookupLocationsFromCache && host.getResolvedModuleWithFailedLookupLocationsFromCache(importLiteral.text, importingSourceFile.fileName, mode); - return getSourceFileToImportFromResolved(importLiteral, resolved, oldToNew, program.getSourceFiles()); + return newFileName === undefined + ? { newFileName: oldFileName, updated: false } + : { newFileName, updated: true }; + } else { + const mode = program.getModeForUsageLocation( + importingSourceFile, + importLiteral + ); + const resolved = + host.resolveModuleNameLiterals || !host.resolveModuleNames + ? program.getResolvedModuleFromModuleSpecifier( + importLiteral, + importingSourceFile + ) + : host.getResolvedModuleWithFailedLookupLocationsFromCache && + host.getResolvedModuleWithFailedLookupLocationsFromCache( + importLiteral.text, + importingSourceFile.fileName, + mode + ); + return getSourceFileToImportFromResolved( + importLiteral, + resolved, + oldToNew, + program.getSourceFiles() + ); } } -function getSourceFileToImportFromResolved(importLiteral: StringLiteralLike, resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater, sourceFiles: readonly SourceFile[]): ToImport | undefined { +function getSourceFileToImportFromResolved( + importLiteral: StringLiteralLike, + resolved: ResolvedModuleWithFailedLookupLocations | undefined, + oldToNew: PathUpdater, + sourceFiles: readonly SourceFile[] +): ToImport | undefined { // Search through all locations looking for a moved file, and only then test already existing files. // This is because if `a.ts` is compiled to `a.js` and `a.ts` is moved, we don't want to resolve anything to `a.js`, but to `a.ts`'s new location. if (!resolved) return undefined; @@ -365,23 +565,40 @@ function getSourceFileToImportFromResolved(importLiteral: StringLiteralLike, res } // Then failed lookups that are in the list of sources - const result = forEach(resolved.failedLookupLocations, tryChangeWithIgnoringPackageJsonExisting) + const result = + forEach( + resolved.failedLookupLocations, + tryChangeWithIgnoringPackageJsonExisting + ) || // Then failed lookups except package.json since we dont want to touch them (only included ts/js files). // At this point, the confidence level of this fix being correct is too low to change bare specifiers or absolute paths. - || pathIsRelative(importLiteral.text) && forEach(resolved.failedLookupLocations, tryChangeWithIgnoringPackageJson); + (pathIsRelative(importLiteral.text) && + forEach( + resolved.failedLookupLocations, + tryChangeWithIgnoringPackageJson + )); if (result) return result; // If nothing changed, then result is resolved module file thats not updated - return resolved.resolvedModule && { newFileName: resolved.resolvedModule.resolvedFileName, updated: false }; + return ( + resolved.resolvedModule && { + newFileName: resolved.resolvedModule.resolvedFileName, + updated: false, + } + ); function tryChangeWithIgnoringPackageJsonExisting(oldFileName: string) { const newFileName = oldToNew(oldFileName); - return newFileName && find(sourceFiles, src => src.fileName === newFileName) - ? tryChangeWithIgnoringPackageJson(oldFileName) : undefined; + return newFileName && + find(sourceFiles, (src) => src.fileName === newFileName) + ? tryChangeWithIgnoringPackageJson(oldFileName) + : undefined; } function tryChangeWithIgnoringPackageJson(oldFileName: string) { - return !endsWith(oldFileName, "/package.json") ? tryChange(oldFileName) : undefined; + return !endsWith(oldFileName, "/package.json") + ? tryChange(oldFileName) + : undefined; } function tryChange(oldFileName: string) { @@ -390,20 +607,41 @@ function getSourceFileToImportFromResolved(importLiteral: StringLiteralLike, res } } -function updateImportsWorker(sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateRef: (refText: string) => string | undefined, updateImport: (importLiteral: StringLiteralLike) => string | undefined, preferences: UserPreferences) { - for (const ref of sourceFile.referencedFiles || emptyArray) { // TODO: GH#26162 +function updateImportsWorker( + sourceFile: SourceFile, + changeTracker: textChanges.ChangeTracker, + updateRef: (refText: string) => string | undefined, + updateImport: (importLiteral: StringLiteralLike) => string | undefined, + preferences: UserPreferences +) { + for (const ref of sourceFile.referencedFiles || emptyArray) { + // TODO: GH#26162 const updated = updateRef(ref.fileName); - if (updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end)) changeTracker.replaceRangeWithText(sourceFile, ref, updated); + if ( + updated !== undefined && + updated !== sourceFile.text.slice(ref.pos, ref.end) + ) + changeTracker.replaceRangeWithText(sourceFile, ref, updated); } for (const importStringLiteral of sourceFile.imports) { const updated = updateImport(importStringLiteral); - if (updated !== undefined && updated !== importStringLiteral.text) changeTracker.replaceRangeWithText(sourceFile, createStringRange(importStringLiteral, sourceFile), updated); + if (updated !== undefined && updated !== importStringLiteral.text) + changeTracker.replaceRangeWithText( + sourceFile, + createStringRange(importStringLiteral, sourceFile), + updated + ); } // Update additional module loading patterns (dynamic import, require, test mocks) // This catches patterns that aren't in sourceFile.imports (like require in .ts files) - updateModuleLoadingCalls(sourceFile, changeTracker, updateImport, preferences); + updateModuleLoadingCalls( + sourceFile, + changeTracker, + updateImport, + preferences + ); } /** @@ -414,7 +652,7 @@ function updateModuleLoadingCalls( sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateImport: (importLiteral: StringLiteralLike) => string | undefined, - preferences: UserPreferences, + preferences: UserPreferences ): void { // Create a set of string literals already processed from sourceFile.imports to avoid duplicates const processedImports = new Set(sourceFile.imports); @@ -445,11 +683,17 @@ function updateModuleLoadingCalls( visitor(sourceFile); } -function createStringRange(node: StringLiteralLike, sourceFile: SourceFileLike): TextRange { +function createStringRange( + node: StringLiteralLike, + sourceFile: SourceFileLike +): TextRange { return createRange(node.getStart(sourceFile) + 1, node.end - 1); } -function forEachProperty(objectLiteral: Expression, cb: (property: PropertyAssignment, propertyName: string) => void) { +function forEachProperty( + objectLiteral: Expression, + cb: (property: PropertyAssignment, propertyName: string) => void +) { if (!isObjectLiteralExpression(objectLiteral)) return; for (const property of objectLiteral.properties) { if (isPropertyAssignment(property) && isStringLiteral(property.name)) { From c216a928d6431d6804b4041ed60343db74978498 Mon Sep 17 00:00:00 2001 From: hjonasson Date: Thu, 4 Dec 2025 14:26:23 +1300 Subject: [PATCH 3/4] Fix API baseline formatting --- tests/baselines/reference/api/typescript.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 9895ad0cbd441..a926b6d072bac 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -8434,7 +8434,7 @@ declare namespace ts { * If enabled, file rename operations will update string literals in test framework * mocking functions such as jest.mock(), vitest.mock(), etc. * - * Default: `false` + * Default: false */ readonly updateImportsInTestFrameworkCalls?: boolean; } From e9c2ce61c98946a35647416b7e7c684cdee6ece0 Mon Sep 17 00:00:00 2001 From: hjonasson Date: Thu, 4 Dec 2025 14:35:43 +1300 Subject: [PATCH 4/4] Apply code formatting --- src/services/getEditsForFileRename.ts | 253 +++++++++++++------------- 1 file changed, 123 insertions(+), 130 deletions(-) diff --git a/src/services/getEditsForFileRename.ts b/src/services/getEditsForFileRename.ts index 7b35bed2e2b5c..7e4a34e0c8641 100644 --- a/src/services/getEditsForFileRename.ts +++ b/src/services/getEditsForFileRename.ts @@ -67,27 +67,27 @@ export function getEditsForFileRename( host: LanguageServiceHost, formatContext: formatting.FormatContext, preferences: UserPreferences, - sourceMapper: SourceMapper + sourceMapper: SourceMapper, ): readonly FileTextChanges[] { const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host); const getCanonicalFileName = createGetCanonicalFileName( - useCaseSensitiveFileNames + useCaseSensitiveFileNames, ); const oldToNew = getPathUpdater( oldFileOrDirPath, newFileOrDirPath, getCanonicalFileName, - sourceMapper + sourceMapper, ); const newToOld = getPathUpdater( newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName, - sourceMapper + sourceMapper, ); return textChanges.ChangeTracker.with( { host, formatContext, preferences }, - (changeTracker) => { + changeTracker => { updateTsconfigFiles( program, changeTracker, @@ -95,7 +95,7 @@ export function getEditsForFileRename( oldFileOrDirPath, newFileOrDirPath, host.getCurrentDirectory(), - useCaseSensitiveFileNames + useCaseSensitiveFileNames, ); updateImports( program, @@ -104,9 +104,9 @@ export function getEditsForFileRename( newToOld, host, getCanonicalFileName, - preferences + preferences, ); - } + }, ); } @@ -122,35 +122,33 @@ export function getPathUpdater( oldFileOrDirPath: string, newFileOrDirPath: string, getCanonicalFileName: GetCanonicalFileName, - sourceMapper: SourceMapper | undefined + sourceMapper: SourceMapper | undefined, ): PathUpdater { const canonicalOldPath = getCanonicalFileName(oldFileOrDirPath); - return (path) => { - const originalPath = - sourceMapper && + return path => { + const originalPath = sourceMapper && sourceMapper.tryGetSourcePosition({ fileName: path, pos: 0 }); const updatedPath = getUpdatedPath( - originalPath ? originalPath.fileName : path + originalPath ? originalPath.fileName : path, ); return originalPath ? updatedPath === undefined ? undefined : makeCorrespondingRelativeChange( - originalPath.fileName, - updatedPath, - path, - getCanonicalFileName - ) + originalPath.fileName, + updatedPath, + path, + getCanonicalFileName, + ) : updatedPath; }; function getUpdatedPath(pathToUpdate: string): string | undefined { - if (getCanonicalFileName(pathToUpdate) === canonicalOldPath) - return newFileOrDirPath; + if (getCanonicalFileName(pathToUpdate) === canonicalOldPath) return newFileOrDirPath; const suffix = tryRemoveDirectoryPrefix( pathToUpdate, canonicalOldPath, - getCanonicalFileName + getCanonicalFileName, ); return suffix === undefined ? undefined @@ -163,7 +161,7 @@ function makeCorrespondingRelativeChange( a0: string, b0: string, a1: string, - getCanonicalFileName: GetCanonicalFileName + getCanonicalFileName: GetCanonicalFileName, ): string { const rel = getRelativePathFromFile(a0, b0, getCanonicalFileName); return combinePathsSafe(getDirectoryPath(a1), rel); @@ -205,7 +203,7 @@ const testFrameworkPatterns: readonly TestFrameworkPattern[] = [ */ function getModulePathArgument( node: CallExpression, - preferences: UserPreferences + preferences: UserPreferences, ): StringLiteralLike | undefined { // Check for dynamic import: import("./module") if (isImportCall(node)) { @@ -241,7 +239,7 @@ function getModulePathArgument( // Find matching pattern const pattern = find( testFrameworkPatterns, - (p) => p.object === objectName && p.method === methodName + p => p.object === objectName && p.method === methodName, ); if (!pattern) { @@ -267,7 +265,7 @@ function updateTsconfigFiles( oldFileOrDirPath: string, newFileOrDirPath: string, currentDirectory: string, - useCaseSensitiveFileNames: boolean + useCaseSensitiveFileNames: boolean, ): void { const { configFile } = program.getCompilerOptions(); if (!configFile) return; @@ -286,11 +284,10 @@ function updateTsconfigFiles( foundExactMatch || propertyName !== "include" || !isArrayLiteralExpression(property.initializer) - ) - return; + ) return; const includes = mapDefined( property.initializer.elements, - (e) => (isStringLiteral(e) ? e.text : undefined) + e => (isStringLiteral(e) ? e.text : undefined), ); if (includes.length === 0) return; const matchers = getFileMatcherPatterns( @@ -298,25 +295,25 @@ function updateTsconfigFiles( /*excludes*/ [], includes, useCaseSensitiveFileNames, - currentDirectory + currentDirectory, ); // If there isn't some include for this, add a new one. if ( getRegexFromPattern( Debug.checkDefined(matchers.includeFilePattern), - useCaseSensitiveFileNames + useCaseSensitiveFileNames, ).test(oldFileOrDirPath) && !getRegexFromPattern( Debug.checkDefined(matchers.includeFilePattern), - useCaseSensitiveFileNames + useCaseSensitiveFileNames, ).test(newFileOrDirPath) ) { changeTracker.insertNodeAfter( configFile, last(property.initializer.elements), factory.createStringLiteral( - relativePath(newFileOrDirPath) - ) + relativePath(newFileOrDirPath), + ), ); } return; @@ -334,24 +331,26 @@ function updateTsconfigFiles( option.element.isFilePath)) ) { updatePaths(property); - } else if (propertyName === "paths") { + } + else if (propertyName === "paths") { forEachProperty( property.initializer, - (pathsProperty) => { + pathsProperty => { if ( !isArrayLiteralExpression( - pathsProperty.initializer + pathsProperty.initializer, ) - ) - return; - for (const e of pathsProperty.initializer - .elements) { + ) return; + for ( + const e of pathsProperty.initializer + .elements + ) { tryUpdateString(e); } - } + }, ); } - } + }, ); return; } @@ -377,7 +376,7 @@ function updateTsconfigFiles( changeTracker.replaceRangeWithText( configFile!, createStringRange(element, configFile!), - relativePath(updated) + relativePath(updated), ); return true; } @@ -388,7 +387,7 @@ function updateTsconfigFiles( return getRelativePathFromDirectory( configDir, path, - /*ignoreCase*/ !useCaseSensitiveFileNames + /*ignoreCase*/ !useCaseSensitiveFileNames, ); } } @@ -400,7 +399,7 @@ function updateImports( newToOld: PathUpdater, host: LanguageServiceHost, getCanonicalFileName: GetCanonicalFileName, - preferences: UserPreferences + preferences: UserPreferences, ): void { const allFiles = program.getSourceFiles(); for (const sourceFile of allFiles) { @@ -412,82 +411,77 @@ function updateImports( const oldImportFromPath: string = oldFromNew || sourceFile.fileName; const oldImportFromDirectory = getDirectoryPath(oldImportFromPath); - const importingSourceFileMoved = - newFromOld !== undefined || oldFromNew !== undefined; + const importingSourceFileMoved = newFromOld !== undefined || oldFromNew !== undefined; updateImportsWorker( sourceFile, changeTracker, - (referenceText) => { + referenceText => { if (!pathIsRelative(referenceText)) return undefined; const oldAbsolute = combinePathsSafe( oldImportFromDirectory, - referenceText + referenceText, ); const newAbsolute = oldToNew(oldAbsolute); return newAbsolute === undefined ? undefined : ensurePathIsNonModuleName( - getRelativePathFromDirectory( - newImportFromDirectory, - newAbsolute, - getCanonicalFileName - ) - ); + getRelativePathFromDirectory( + newImportFromDirectory, + newAbsolute, + getCanonicalFileName, + ), + ); }, - (importLiteral) => { + importLiteral => { const importedModuleSymbol = program .getTypeChecker() .getSymbolAtLocation(importLiteral); // No need to update if it's an ambient module^M if ( importedModuleSymbol?.declarations && - importedModuleSymbol.declarations.some((d) => - isAmbientModule(d) + importedModuleSymbol.declarations.some(d => isAmbientModule(d)) + ) return undefined; + + const toImport = oldFromNew !== undefined + // If we're at the new location (file was already renamed), need to redo module resolution starting from the old location. + // TODO:GH#18217 + ? getSourceFileToImportFromResolved( + importLiteral, + resolveModuleName( + importLiteral.text, + oldImportFromPath, + program.getCompilerOptions(), + host as ModuleResolutionHost, + ), + oldToNew, + allFiles, ) - ) - return undefined; - - const toImport = - oldFromNew !== undefined - ? // If we're at the new location (file was already renamed), need to redo module resolution starting from the old location. - // TODO:GH#18217 - getSourceFileToImportFromResolved( - importLiteral, - resolveModuleName( - importLiteral.text, - oldImportFromPath, - program.getCompilerOptions(), - host as ModuleResolutionHost - ), - oldToNew, - allFiles - ) - : getSourceFileToImport( - importedModuleSymbol, - importLiteral, - sourceFile, - program, - host, - oldToNew - ); + : getSourceFileToImport( + importedModuleSymbol, + importLiteral, + sourceFile, + program, + host, + oldToNew, + ); // Need an update if the imported file moved, or the importing file moved and was using a relative path. return toImport !== undefined && - (toImport.updated || - (importingSourceFileMoved && - pathIsRelative(importLiteral.text))) + (toImport.updated || + (importingSourceFileMoved && + pathIsRelative(importLiteral.text))) ? moduleSpecifiers.updateModuleSpecifier( - program.getCompilerOptions(), - sourceFile, - newImportFromPath, - toImport.newFileName, - createModuleSpecifierResolutionHost(program, host), - importLiteral.text - ) + program.getCompilerOptions(), + sourceFile, + newImportFromPath, + toImport.newFileName, + createModuleSpecifierResolutionHost(program, host), + importLiteral.text, + ) : undefined; }, - preferences + preferences, ); } } @@ -510,40 +504,40 @@ function getSourceFileToImport( importingSourceFile: SourceFile, program: Program, host: LanguageServiceHost, - oldToNew: PathUpdater + oldToNew: PathUpdater, ): ToImport | undefined { if (importedModuleSymbol) { // `find` should succeed because we checked for ambient modules before calling this function. const oldFileName = find( importedModuleSymbol.declarations, - isSourceFile + isSourceFile, )!.fileName; const newFileName = oldToNew(oldFileName); return newFileName === undefined ? { newFileName: oldFileName, updated: false } : { newFileName, updated: true }; - } else { + } + else { const mode = program.getModeForUsageLocation( importingSourceFile, - importLiteral + importLiteral, ); - const resolved = - host.resolveModuleNameLiterals || !host.resolveModuleNames - ? program.getResolvedModuleFromModuleSpecifier( - importLiteral, - importingSourceFile - ) - : host.getResolvedModuleWithFailedLookupLocationsFromCache && - host.getResolvedModuleWithFailedLookupLocationsFromCache( - importLiteral.text, - importingSourceFile.fileName, - mode - ); + const resolved = host.resolveModuleNameLiterals || !host.resolveModuleNames + ? program.getResolvedModuleFromModuleSpecifier( + importLiteral, + importingSourceFile, + ) + : host.getResolvedModuleWithFailedLookupLocationsFromCache && + host.getResolvedModuleWithFailedLookupLocationsFromCache( + importLiteral.text, + importingSourceFile.fileName, + mode, + ); return getSourceFileToImportFromResolved( importLiteral, resolved, oldToNew, - program.getSourceFiles() + program.getSourceFiles(), ); } } @@ -552,7 +546,7 @@ function getSourceFileToImportFromResolved( importLiteral: StringLiteralLike, resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater, - sourceFiles: readonly SourceFile[] + sourceFiles: readonly SourceFile[], ): ToImport | undefined { // Search through all locations looking for a moved file, and only then test already existing files. // This is because if `a.ts` is compiled to `a.js` and `a.ts` is moved, we don't want to resolve anything to `a.js`, but to `a.ts`'s new location. @@ -565,17 +559,16 @@ function getSourceFileToImportFromResolved( } // Then failed lookups that are in the list of sources - const result = - forEach( - resolved.failedLookupLocations, - tryChangeWithIgnoringPackageJsonExisting - ) || + const result = forEach( + resolved.failedLookupLocations, + tryChangeWithIgnoringPackageJsonExisting, + ) || // Then failed lookups except package.json since we dont want to touch them (only included ts/js files). // At this point, the confidence level of this fix being correct is too low to change bare specifiers or absolute paths. (pathIsRelative(importLiteral.text) && forEach( resolved.failedLookupLocations, - tryChangeWithIgnoringPackageJson + tryChangeWithIgnoringPackageJson, )); if (result) return result; @@ -590,7 +583,7 @@ function getSourceFileToImportFromResolved( function tryChangeWithIgnoringPackageJsonExisting(oldFileName: string) { const newFileName = oldToNew(oldFileName); return newFileName && - find(sourceFiles, (src) => src.fileName === newFileName) + find(sourceFiles, src => src.fileName === newFileName) ? tryChangeWithIgnoringPackageJson(oldFileName) : undefined; } @@ -612,7 +605,7 @@ function updateImportsWorker( changeTracker: textChanges.ChangeTracker, updateRef: (refText: string) => string | undefined, updateImport: (importLiteral: StringLiteralLike) => string | undefined, - preferences: UserPreferences + preferences: UserPreferences, ) { for (const ref of sourceFile.referencedFiles || emptyArray) { // TODO: GH#26162 @@ -620,18 +613,18 @@ function updateImportsWorker( if ( updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end) - ) - changeTracker.replaceRangeWithText(sourceFile, ref, updated); + ) changeTracker.replaceRangeWithText(sourceFile, ref, updated); } for (const importStringLiteral of sourceFile.imports) { const updated = updateImport(importStringLiteral); - if (updated !== undefined && updated !== importStringLiteral.text) + if (updated !== undefined && updated !== importStringLiteral.text) { changeTracker.replaceRangeWithText( sourceFile, createStringRange(importStringLiteral, sourceFile), - updated + updated, ); + } } // Update additional module loading patterns (dynamic import, require, test mocks) @@ -640,7 +633,7 @@ function updateImportsWorker( sourceFile, changeTracker, updateImport, - preferences + preferences, ); } @@ -652,7 +645,7 @@ function updateModuleLoadingCalls( sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateImport: (importLiteral: StringLiteralLike) => string | undefined, - preferences: UserPreferences + preferences: UserPreferences, ): void { // Create a set of string literals already processed from sourceFile.imports to avoid duplicates const processedImports = new Set(sourceFile.imports); @@ -669,7 +662,7 @@ function updateModuleLoadingCalls( changeTracker.replaceRangeWithText( sourceFile, createStringRange(pathArgument, sourceFile), - updated + updated, ); } } @@ -685,14 +678,14 @@ function updateModuleLoadingCalls( function createStringRange( node: StringLiteralLike, - sourceFile: SourceFileLike + sourceFile: SourceFileLike, ): TextRange { return createRange(node.getStart(sourceFile) + 1, node.end - 1); } function forEachProperty( objectLiteral: Expression, - cb: (property: PropertyAssignment, propertyName: string) => void + cb: (property: PropertyAssignment, propertyName: string) => void, ) { if (!isObjectLiteralExpression(objectLiteral)) return; for (const property of objectLiteral.properties) {