1
1
import type { TSESTree } from '@typescript-eslint/experimental-utils' ;
2
2
import { createESLintRule } from '../utils/create-eslint-rule' ;
3
- import { OUTPUT_DECORATOR } from '../utils/selectors' ;
4
- import { toPattern } from '../utils/utils' ;
3
+ import { getNativeEventNames } from '../utils/get-native-event-names' ;
4
+ import {
5
+ OUTPUTS_METADATA_PROPERTY ,
6
+ OUTPUT_ALIAS ,
7
+ OUTPUT_PROPERTY_OR_GETTER ,
8
+ } from '../utils/selectors' ;
9
+ import { getRawText } from '../utils/utils' ;
5
10
6
11
type Options = [ ] ;
7
12
export type MessageIds = 'noOutputNative' ;
@@ -12,27 +17,44 @@ export default createESLintRule<Options, MessageIds>({
12
17
meta : {
13
18
type : 'suggestion' ,
14
19
docs : {
15
- description : 'Disallows naming or aliasing outputs as standard DOM event' ,
20
+ description :
21
+ 'Ensures that output bindings, including aliases, are not named as standard DOM events' ,
16
22
category : 'Best Practices' ,
17
23
recommended : 'error' ,
18
24
} ,
19
25
schema : [ ] ,
20
26
messages : {
21
27
noOutputNative :
22
- 'Outputs should not be named or aliased as standard DOM event ' ,
28
+ 'Output bindings, including aliases, should not be named as standard DOM events ' ,
23
29
} ,
24
30
} ,
25
31
defaultOptions : [ ] ,
26
32
create ( context ) {
27
- const nativeEventNames = toPattern ( [ ...getNativeEventNames ( ) ] ) ;
28
- const outputAliasSelector = `ClassProperty ${ OUTPUT_DECORATOR } :matches(Literal[value=${ nativeEventNames } ], TemplateElement[value.raw=${ nativeEventNames } ])` ;
29
- const outputPropertySelector = `ClassProperty[computed=false]:has(${ OUTPUT_DECORATOR } ) > :matches(Identifier[name=${ nativeEventNames } ], Literal[value=${ nativeEventNames } ])` ;
30
- const selectors = [ outputAliasSelector , outputPropertySelector ] . join ( ',' ) ;
33
+ const nativeEventNames = getNativeEventNames ( ) ;
34
+ const selectors = [
35
+ OUTPUTS_METADATA_PROPERTY ,
36
+ OUTPUT_ALIAS ,
37
+ OUTPUT_PROPERTY_OR_GETTER ,
38
+ ] . join ( ',' ) ;
31
39
32
40
return {
33
41
[ selectors ] (
34
- node : TSESTree . Identifier | TSESTree . Literal | TSESTree . TemplateElement ,
42
+ node :
43
+ | TSESTree . Identifier
44
+ | TSESTree . StringLiteral
45
+ | TSESTree . TemplateElement ,
35
46
) {
47
+ const [ propertyName , aliasName ] = getRawText ( node )
48
+ . replace ( / \s / g, '' )
49
+ . split ( ':' ) ;
50
+
51
+ if (
52
+ ! nativeEventNames . has ( propertyName ) &&
53
+ ! nativeEventNames . has ( aliasName )
54
+ ) {
55
+ return ;
56
+ }
57
+
36
58
context . report ( {
37
59
node,
38
60
messageId : 'noOutputNative' ,
@@ -41,184 +63,3 @@ export default createESLintRule<Options, MessageIds>({
41
63
} ;
42
64
} ,
43
65
} ) ;
44
-
45
- let nativeEventNames : ReadonlySet < string > | null = null ;
46
- function getNativeEventNames ( ) : ReadonlySet < string > {
47
- return (
48
- nativeEventNames ||
49
- // Source: https://developer.mozilla.org/en-US/docs/Web/Events
50
- ( nativeEventNames = new Set < string > ( [
51
- 'abort' ,
52
- 'afterprint' ,
53
- 'animationend' ,
54
- 'animationiteration' ,
55
- 'animationstart' ,
56
- 'appinstalled' ,
57
- 'audioprocess' ,
58
- 'audioend' ,
59
- 'audiostart' ,
60
- 'beforeprint' ,
61
- 'beforeunload' ,
62
- 'beginEvent' ,
63
- 'blocked' ,
64
- 'blur' ,
65
- 'boundary' ,
66
- 'cached' ,
67
- 'canplay' ,
68
- 'canplaythrough' ,
69
- 'change' ,
70
- 'chargingchange' ,
71
- 'chargingtimechange' ,
72
- 'checking' ,
73
- 'click' ,
74
- 'close' ,
75
- 'complete' ,
76
- 'compositionend' ,
77
- 'compositionstart' ,
78
- 'compositionupdate' ,
79
- 'contextmenu' ,
80
- 'copy' ,
81
- 'cut' ,
82
- 'dblclick' ,
83
- 'devicechange' ,
84
- 'devicelight' ,
85
- 'devicemotion' ,
86
- 'deviceorientation' ,
87
- 'deviceproximity' ,
88
- 'dischargingtimechange' ,
89
- 'DOMAttributeNameChanged' ,
90
- 'DOMAttrModified' ,
91
- 'DOMCharacterDataModified' ,
92
- 'DOMContentLoaded' ,
93
- 'DOMElementNameChanged' ,
94
- 'focus' ,
95
- 'focusin' ,
96
- 'focusout' ,
97
- 'DOMNodeInserted' ,
98
- 'DOMNodeInsertedIntoDocument' ,
99
- 'DOMNodeRemoved' ,
100
- 'DOMNodeRemovedFromDocument' ,
101
- 'DOMSubtreeModified' ,
102
- 'downloading' ,
103
- 'drag' ,
104
- 'dragend' ,
105
- 'dragenter' ,
106
- 'dragleave' ,
107
- 'dragover' ,
108
- 'dragstart' ,
109
- 'drop' ,
110
- 'durationchange' ,
111
- 'emptied' ,
112
- 'end' ,
113
- 'ended' ,
114
- 'endEvent' ,
115
- 'error' ,
116
- 'fullscreenchange' ,
117
- 'fullscreenerror' ,
118
- 'gamepadconnected' ,
119
- 'gamepaddisconnected' ,
120
- 'gotpointercapture' ,
121
- 'hashchange' ,
122
- 'lostpointercapture' ,
123
- 'input' ,
124
- 'invalid' ,
125
- 'keydown' ,
126
- 'keypress' ,
127
- 'keyup' ,
128
- 'languagechange' ,
129
- 'levelchange' ,
130
- 'load' ,
131
- 'loadeddata' ,
132
- 'loadedmetadata' ,
133
- 'loadend' ,
134
- 'loadstart' ,
135
- 'mark' ,
136
- 'message' ,
137
- 'messageerror' ,
138
- 'mousedown' ,
139
- 'mouseenter' ,
140
- 'mouseleave' ,
141
- 'mousemove' ,
142
- 'mouseout' ,
143
- 'mouseover' ,
144
- 'mouseup' ,
145
- 'nomatch' ,
146
- 'notificationclick' ,
147
- 'noupdate' ,
148
- 'obsolete' ,
149
- 'offline' ,
150
- 'online' ,
151
- 'open' ,
152
- 'orientationchange' ,
153
- 'pagehide' ,
154
- 'pageshow' ,
155
- 'paste' ,
156
- 'pause' ,
157
- 'pointercancel' ,
158
- 'pointerdown' ,
159
- 'pointerenter' ,
160
- 'pointerleave' ,
161
- 'pointerlockchange' ,
162
- 'pointerlockerror' ,
163
- 'pointermove' ,
164
- 'pointerout' ,
165
- 'pointerover' ,
166
- 'pointerup' ,
167
- 'play' ,
168
- 'playing' ,
169
- 'popstate' ,
170
- 'progress' ,
171
- 'push' ,
172
- 'pushsubscriptionchange' ,
173
- 'ratechange' ,
174
- 'readystatechange' ,
175
- 'repeatEvent' ,
176
- 'reset' ,
177
- 'resize' ,
178
- 'resourcetimingbufferfull' ,
179
- 'result' ,
180
- 'resume' ,
181
- 'scroll' ,
182
- 'seeked' ,
183
- 'seeking' ,
184
- 'select' ,
185
- 'selectstart' ,
186
- 'selectionchange' ,
187
- 'show' ,
188
- 'soundend' ,
189
- 'soundstart' ,
190
- 'speechend' ,
191
- 'speechstart' ,
192
- 'stalled' ,
193
- 'start' ,
194
- 'storage' ,
195
- 'submit' ,
196
- 'success' ,
197
- 'suspend' ,
198
- 'SVGAbort' ,
199
- 'SVGError' ,
200
- 'SVGLoad' ,
201
- 'SVGResize' ,
202
- 'SVGScroll' ,
203
- 'SVGUnload' ,
204
- 'SVGZoom' ,
205
- 'timeout' ,
206
- 'timeupdate' ,
207
- 'touchcancel' ,
208
- 'touchend' ,
209
- 'touchmove' ,
210
- 'touchstart' ,
211
- 'transitionend' ,
212
- 'unload' ,
213
- 'updateready' ,
214
- 'upgradeneeded' ,
215
- 'userproximity' ,
216
- 'voiceschanged' ,
217
- 'versionchange' ,
218
- 'visibilitychange' ,
219
- 'volumechange' ,
220
- 'waiting' ,
221
- 'wheel' ,
222
- ] ) )
223
- ) ;
224
- }
0 commit comments