@@ -54,111 +54,100 @@ export const noImportOperatorsRule = ruleCreator({
54
54
return undefined ;
55
55
}
56
56
57
+ function hasDeprecatedOperators ( specifiers ?: es . ImportSpecifier [ ] | es . ExportSpecifier [ ] ) : boolean {
58
+ return ! ! specifiers ?. some ( s => DEPRECATED_OPERATORS . includes ( getName ( getOperatorNode ( s ) ) ) ) ;
59
+ }
60
+
57
61
function getName ( node : es . Identifier | es . StringLiteral ) : string {
58
62
return isIdentifier ( node ) ? node . name : node . value ;
59
63
}
60
64
61
- function getSpecifierReplacement ( name : string ) : string | undefined {
65
+ function getOperatorNode ( node : es . ImportSpecifier | es . ExportSpecifier ) : es . Identifier | es . StringLiteral {
66
+ return isImportSpecifier ( node ) ? node . imported : node . local ;
67
+ }
68
+
69
+ function getAliasNode ( node : es . ImportSpecifier | es . ExportSpecifier ) : es . Identifier | es . StringLiteral {
70
+ return isImportSpecifier ( node ) ? node . local : node . exported ;
71
+ }
72
+
73
+ function getOperatorReplacement ( name : string ) : string | undefined {
62
74
return RENAMED_OPERATORS [ name ] ;
63
75
}
64
76
65
- function reportNode ( source : es . Literal , importSpecifiers ?: es . ImportSpecifier [ ] , exportSpecifiers ?: es . ExportSpecifier [ ] ) : void {
66
- const replacement = getSourceReplacement ( source . raw ) ;
67
- if (
68
- replacement
69
- && ! importSpecifiers ?. some ( s => DEPRECATED_OPERATORS . includes ( getName ( s . imported ) ) )
70
- && ! exportSpecifiers ?. some ( s => DEPRECATED_OPERATORS . includes ( getName ( s . exported ) ) )
71
- ) {
72
- if ( importSpecifiers ) {
73
- function * fix ( fixer : TSESLint . RuleFixer ) {
74
- // Rename the module name.
75
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
76
- yield fixer . replaceText ( source , replacement ! ) ;
77
-
78
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
79
- for ( const specifier of importSpecifiers ! ) {
80
- const operatorName = getName ( specifier . imported ) ;
81
- const specifierReplacement = getSpecifierReplacement ( operatorName ) ;
82
- if ( specifierReplacement ) {
83
- if ( specifier . local . name === operatorName ) {
84
- // concat -> concatWith as concat
85
- yield fixer . insertTextBefore ( specifier . imported , specifierReplacement + ' as ' ) ;
86
- } else if ( isIdentifier ( specifier . imported ) ) {
87
- // concat as c -> concatWith as c
88
- yield fixer . replaceText ( specifier . imported , specifierReplacement ) ;
89
- } else {
90
- // 'concat' as c -> 'concatWith' as c
91
- const quote = getQuote ( specifier . imported . raw ) ;
92
- if ( ! quote ) {
93
- continue ;
94
- }
95
- yield fixer . replaceText ( specifier . imported , quote + specifierReplacement + quote ) ;
96
- }
97
- }
98
- }
77
+ function isNodesEqual ( a : es . Node , b : es . Node ) : boolean {
78
+ return a . range [ 0 ] === b . range [ 0 ] && a . range [ 1 ] === b . range [ 1 ] ;
79
+ }
80
+
81
+ function createFix ( source : es . Node , replacement : string , specifiers : es . ImportSpecifier [ ] | es . ExportSpecifier [ ] ) {
82
+ return function * fix ( fixer : TSESLint . RuleFixer ) {
83
+ // Rename the module name.
84
+ yield fixer . replaceText ( source , replacement ) ;
85
+
86
+ // Rename the imported operators if necessary.
87
+ for ( const specifier of specifiers ) {
88
+ const operatorNode = getOperatorNode ( specifier ) ;
89
+ const operatorName = getName ( operatorNode ) ;
90
+
91
+ const operatorReplacement = getOperatorReplacement ( operatorName ) ;
92
+ if ( ! operatorReplacement ) {
93
+ // The operator has the same name.
94
+ continue ;
99
95
}
100
- context . report ( {
101
- fix,
102
- messageId : 'forbidden' ,
103
- node : source ,
104
- suggest : [ { messageId : 'suggest' , fix } ] ,
105
- } ) ;
106
- } else if ( exportSpecifiers ) {
107
- function * fix ( fixer : TSESLint . RuleFixer ) {
108
- // Rename the module name.
109
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
110
- yield fixer . replaceText ( source , replacement ! ) ;
111
-
112
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
113
- for ( const specifier of exportSpecifiers ! ) {
114
- const operatorName = getName ( specifier . local ) ;
115
- const specifierReplacement = getSpecifierReplacement ( operatorName ) ;
116
- if ( specifierReplacement ) {
117
- const exportedName = getName ( specifier . exported ) ;
118
- if ( exportedName === operatorName ) {
119
- // concat -> concatWith as concat
120
- yield fixer . insertTextBefore ( specifier . exported , specifierReplacement + ' as ' ) ;
121
- } else if ( isIdentifier ( specifier . local ) ) {
122
- // concat as c -> concatWith as c
123
- yield fixer . replaceText ( specifier . local , specifierReplacement ) ;
124
- } else {
125
- // 'concat' as c -> 'concatWith' as c
126
- const quote = getQuote ( specifier . local . raw ) ;
127
- if ( ! quote ) {
128
- continue ;
129
- }
130
- yield fixer . replaceText ( specifier . local , quote + specifierReplacement + quote ) ;
131
- }
132
- }
96
+
97
+ const aliasNode = getAliasNode ( specifier ) ;
98
+ if ( isNodesEqual ( aliasNode , operatorNode ) ) {
99
+ // concat -> concatWith as concat
100
+ yield fixer . insertTextBefore ( operatorNode , operatorReplacement + ' as ' ) ;
101
+ } else if ( isIdentifier ( operatorNode ) ) {
102
+ // concat as c -> concatWith as c
103
+ yield fixer . replaceText ( operatorNode , operatorReplacement ) ;
104
+ } else {
105
+ // 'concat' as c -> 'concatWith' as c
106
+ const quote = getQuote ( operatorNode . raw ) ;
107
+ if ( ! quote ) {
108
+ continue ;
133
109
}
110
+ yield fixer . replaceText ( operatorNode , quote + operatorReplacement + quote ) ;
134
111
}
135
- context . report ( {
136
- fix,
137
- messageId : 'forbidden' ,
138
- node : source ,
139
- suggest : [ { messageId : 'suggest' , fix } ] ,
140
- } ) ;
141
- } else {
142
- context . report ( {
143
- messageId : 'forbidden' ,
144
- node : source ,
145
- suggest : [ { messageId : 'suggest' , fix : ( fixer ) => fixer . replaceText ( source , replacement ) } ] ,
146
- } ) ;
147
112
}
148
- } else {
113
+ } ;
114
+ }
115
+
116
+ function reportNode ( source : es . Literal , specifiers ?: es . ImportSpecifier [ ] | es . ExportSpecifier [ ] ) : void {
117
+ const replacement = getSourceReplacement ( source . raw ) ;
118
+ if ( ! replacement || hasDeprecatedOperators ( specifiers ) ) {
119
+ context . report ( {
120
+ messageId : 'forbidden' ,
121
+ node : source ,
122
+ } ) ;
123
+ return ;
124
+ }
125
+
126
+ if ( ! specifiers ) {
149
127
context . report ( {
150
128
messageId : 'forbidden' ,
151
129
node : source ,
130
+ suggest : [ { messageId : 'suggest' , fix : ( fixer ) => fixer . replaceText ( source , replacement ) } ] ,
152
131
} ) ;
132
+ return ;
153
133
}
134
+
135
+ const fix = createFix ( source , replacement , specifiers ) ;
136
+ context . report ( {
137
+ fix,
138
+ messageId : 'forbidden' ,
139
+ node : source ,
140
+ suggest : [ { messageId : 'suggest' , fix } ] ,
141
+ } ) ;
154
142
}
155
143
156
144
return {
157
145
'ImportDeclaration[source.value="rxjs/operators"]' : ( node : es . ImportDeclaration ) => {
158
146
// Exclude side effect imports, default imports, and namespace imports.
159
- const specifiers = node . specifiers . length && node . specifiers . every ( s => isImportSpecifier ( s ) )
147
+ const specifiers = node . specifiers . length && node . specifiers . every ( importClause => isImportSpecifier ( importClause ) )
160
148
? node . specifiers
161
149
: undefined ;
150
+
162
151
reportNode ( node . source , specifiers ) ;
163
152
} ,
164
153
'ImportExpression[source.value="rxjs/operators"]' : ( node : es . ImportExpression ) => {
@@ -167,7 +156,7 @@ export const noImportOperatorsRule = ruleCreator({
167
156
}
168
157
} ,
169
158
'ExportNamedDeclaration[source.value="rxjs/operators"]' : ( node : es . ExportNamedDeclarationWithSource ) => {
170
- reportNode ( node . source , undefined , node . specifiers ) ;
159
+ reportNode ( node . source , node . specifiers ) ;
171
160
} ,
172
161
'ExportAllDeclaration[source.value="rxjs/operators"]' : ( node : es . ExportAllDeclaration ) => {
173
162
reportNode ( node . source ) ;
0 commit comments