11/* @internal */
22namespace ts . Rename {
3- export function getRenameInfo ( program : Program , sourceFile : SourceFile , position : number , options ?: RenameInfoOptions ) : RenameInfo {
3+ export function getRenameInfo ( program : Program , sourceFile : SourceFile , position : number , preferences : UserPreferences ) : RenameInfo {
44 const node = getAdjustedRenameLocation ( getTouchingPropertyName ( sourceFile , position ) ) ;
55 if ( nodeIsEligibleForRename ( node ) ) {
6- const renameInfo = getRenameInfoForNode ( node , program . getTypeChecker ( ) , sourceFile , program , options ) ;
6+ const renameInfo = getRenameInfoForNode ( node , program . getTypeChecker ( ) , sourceFile , program , preferences ) ;
77 if ( renameInfo ) {
88 return renameInfo ;
99 }
1010 }
1111 return getRenameInfoError ( Diagnostics . You_cannot_rename_this_element ) ;
1212 }
1313
14- function getRenameInfoForNode ( node : Node , typeChecker : TypeChecker , sourceFile : SourceFile , program : Program , options ?: RenameInfoOptions ) : RenameInfo | undefined {
14+ function getRenameInfoForNode (
15+ node : Node ,
16+ typeChecker : TypeChecker ,
17+ sourceFile : SourceFile ,
18+ program : Program ,
19+ preferences : UserPreferences ) : RenameInfo | undefined {
1520 const symbol = typeChecker . getSymbolAtLocation ( node ) ;
1621 if ( ! symbol ) {
1722 if ( isStringLiteralLike ( node ) ) {
@@ -43,7 +48,13 @@ namespace ts.Rename {
4348 }
4449
4550 if ( isStringLiteralLike ( node ) && tryGetImportFromModuleSpecifier ( node ) ) {
46- return options && options . allowRenameOfImportPath ? getRenameInfoForModule ( node , sourceFile , symbol ) : undefined ;
51+ return preferences . allowRenameOfImportPath ? getRenameInfoForModule ( node , sourceFile , symbol ) : undefined ;
52+ }
53+
54+ // Disallow rename for elements that would rename across `*/node_modules/*` packages.
55+ const wouldRenameNodeModules = wouldRenameInOtherNodeModules ( sourceFile , symbol , typeChecker , preferences ) ;
56+ if ( wouldRenameNodeModules ) {
57+ return getRenameInfoError ( wouldRenameNodeModules ) ;
4758 }
4859
4960 const kind = SymbolDisplay . getSymbolKind ( typeChecker , symbol , node ) ;
@@ -60,6 +71,55 @@ namespace ts.Rename {
6071 return program . isSourceFileDefaultLibrary ( sourceFile ) && fileExtensionIs ( sourceFile . fileName , Extension . Dts ) ;
6172 }
6273
74+ function wouldRenameInOtherNodeModules (
75+ originalFile : SourceFile ,
76+ symbol : Symbol ,
77+ checker : TypeChecker ,
78+ preferences : UserPreferences
79+ ) : DiagnosticMessage | undefined {
80+ if ( ! preferences . providePrefixAndSuffixTextForRename && symbol . flags & SymbolFlags . Alias ) {
81+ const importSpecifier = symbol . declarations && find ( symbol . declarations , decl => isImportSpecifier ( decl ) ) ;
82+ if ( importSpecifier && ! ( importSpecifier as ImportSpecifier ) . propertyName ) {
83+ symbol = checker . getAliasedSymbol ( symbol ) ;
84+ }
85+ }
86+ const { declarations } = symbol ;
87+ if ( ! declarations ) {
88+ return undefined ;
89+ }
90+ const originalPackage = getPackagePathComponents ( originalFile . path ) ;
91+ if ( originalPackage === undefined ) { // original source file is not in node_modules
92+ if ( some ( declarations , declaration => isInsideNodeModules ( declaration . getSourceFile ( ) . path ) ) ) {
93+ return Diagnostics . You_cannot_rename_elements_that_are_defined_in_a_node_modules_folder ;
94+ }
95+ else {
96+ return undefined ;
97+ }
98+ }
99+ // original source file is in node_modules
100+ for ( const declaration of declarations ) {
101+ const declPackage = getPackagePathComponents ( declaration . getSourceFile ( ) . path ) ;
102+ if ( declPackage ) {
103+ const length = Math . min ( originalPackage . length , declPackage . length ) ;
104+ for ( let i = 0 ; i <= length ; i ++ ) {
105+ if ( compareStringsCaseSensitive ( originalPackage [ i ] , declPackage [ i ] ) !== Comparison . EqualTo ) {
106+ return Diagnostics . You_cannot_rename_elements_that_are_defined_in_another_node_modules_folder ;
107+ }
108+ }
109+ }
110+ }
111+ return undefined ;
112+ }
113+
114+ function getPackagePathComponents ( filePath : Path ) : string [ ] | undefined {
115+ const components = getPathComponents ( filePath ) ;
116+ const nodeModulesIdx = components . lastIndexOf ( "node_modules" ) ;
117+ if ( nodeModulesIdx === - 1 ) {
118+ return undefined ;
119+ }
120+ return components . slice ( 0 , nodeModulesIdx + 2 ) ;
121+ }
122+
63123 function getRenameInfoForModule ( node : StringLiteralLike , sourceFile : SourceFile , moduleSymbol : Symbol ) : RenameInfo | undefined {
64124 if ( ! isExternalModuleNameRelative ( node . text ) ) {
65125 return getRenameInfoError ( Diagnostics . You_cannot_rename_a_module_via_a_global_import ) ;
0 commit comments