1
1
'use strict' ;
2
- const isShadowed = require ( './utils/is-shadowed.js' ) ;
3
- const {
4
- referenceIdentifierSelector,
5
- callExpressionSelector,
6
- } = require ( './selectors/index.js' ) ;
2
+ const { ReferenceTracker} = require ( 'eslint-utils' ) ;
7
3
const { replaceReferenceIdentifier} = require ( './fix/index.js' ) ;
8
4
const { fixSpaceAroundKeyword} = require ( './fix/index.js' ) ;
9
5
@@ -25,102 +21,102 @@ const methods = {
25
21
isFinite : false ,
26
22
} ;
27
23
28
- const methodsSelector = [
29
- callExpressionSelector ( Object . keys ( methods ) ) ,
30
- ' > ' ,
31
- '.callee' ,
32
- ] . join ( '' ) ;
33
-
34
- const propertiesSelector = referenceIdentifierSelector ( [ 'NaN' , 'Infinity' ] ) ;
35
-
36
24
const isNegative = node => {
37
25
const { parent} = node ;
38
26
return parent && parent . type === 'UnaryExpression' && parent . operator === '-' && parent . argument === node ;
39
27
} ;
40
28
29
+ function * checkMethods ( { sourceCode, tracker} ) {
30
+ const traceMap = Object . fromEntries (
31
+ Object . keys ( methods ) . map ( name => [ name , { [ ReferenceTracker . CALL ] : true } ] ) ,
32
+ ) ;
33
+
34
+ for ( const { node : callExpression , path : [ name ] } of tracker . iterateGlobalReferences ( traceMap ) ) {
35
+ const node = callExpression . callee ;
36
+ const isSafe = methods [ name ] ;
37
+
38
+ const problem = {
39
+ node,
40
+ messageId : METHOD_ERROR_MESSAGE_ID ,
41
+ data : {
42
+ name,
43
+ } ,
44
+ } ;
45
+
46
+ const fix = fixer => replaceReferenceIdentifier ( node , `Number.${ name } ` , fixer , sourceCode ) ;
47
+
48
+ if ( isSafe ) {
49
+ problem . fix = fix ;
50
+ } else {
51
+ problem . suggest = [
52
+ {
53
+ messageId : METHOD_SUGGESTION_MESSAGE_ID ,
54
+ data : {
55
+ name,
56
+ } ,
57
+ fix,
58
+ } ,
59
+ ] ;
60
+ }
61
+
62
+ yield problem ;
63
+ }
64
+ }
65
+
66
+ function * checkProperties ( { sourceCode, tracker, checkInfinity} ) {
67
+ const properties = checkInfinity ? [ 'NaN' , 'Infinity' ] : [ 'NaN' ] ;
68
+ const traceMap = Object . fromEntries (
69
+ properties . map ( name => [ name , { [ ReferenceTracker . READ ] : true } ] ) ,
70
+ ) ;
71
+
72
+ for ( const { node, path : [ name ] } of tracker . iterateGlobalReferences ( traceMap ) ) {
73
+ const { parent} = node ;
74
+
75
+ let property = name ;
76
+ if ( name === 'Infinity' ) {
77
+ property = isNegative ( node ) ? 'NEGATIVE_INFINITY' : 'POSITIVE_INFINITY' ;
78
+ }
79
+
80
+ const problem = {
81
+ node,
82
+ messageId : PROPERTY_ERROR_MESSAGE_ID ,
83
+ data : {
84
+ identifier : name ,
85
+ property,
86
+ } ,
87
+ } ;
88
+
89
+ if ( property === 'NEGATIVE_INFINITY' ) {
90
+ problem . node = parent ;
91
+ problem . data . identifier = '-Infinity' ;
92
+ problem . fix = function * ( fixer ) {
93
+ yield fixer . replaceText ( parent , 'Number.NEGATIVE_INFINITY' ) ;
94
+ yield * fixSpaceAroundKeyword ( fixer , parent , sourceCode ) ;
95
+ } ;
96
+ } else {
97
+ problem . fix = fixer => replaceReferenceIdentifier ( node , `Number.${ property } ` , fixer , sourceCode ) ;
98
+ }
99
+
100
+ yield problem ;
101
+ }
102
+ }
103
+
41
104
/** @param {import('eslint').Rule.RuleContext } context */
42
105
const create = context => {
43
- const sourceCode = context . getSourceCode ( ) ;
44
- const options = {
106
+ const {
107
+ checkInfinity,
108
+ } = {
45
109
checkInfinity : true ,
46
110
...context . options [ 0 ] ,
47
111
} ;
48
112
49
- // Cache `NaN` and `Infinity` in `foo = {NaN, Infinity}`
50
- const reported = new WeakSet ( ) ;
51
-
52
113
return {
53
- [ methodsSelector ] ( node ) {
54
- if ( isShadowed ( context . getScope ( ) , node ) ) {
55
- return ;
56
- }
57
-
58
- const { name} = node ;
59
- const isSafe = methods [ name ] ;
60
-
61
- const problem = {
62
- node,
63
- messageId : METHOD_ERROR_MESSAGE_ID ,
64
- data : {
65
- name,
66
- } ,
67
- } ;
68
-
69
- const fix = fixer => replaceReferenceIdentifier ( node , `Number.${ name } ` , fixer , sourceCode ) ;
70
-
71
- if ( isSafe ) {
72
- problem . fix = fix ;
73
- } else {
74
- problem . suggest = [
75
- {
76
- messageId : METHOD_SUGGESTION_MESSAGE_ID ,
77
- data : {
78
- name,
79
- } ,
80
- fix,
81
- } ,
82
- ] ;
83
- }
84
-
85
- return problem ;
86
- } ,
87
- [ propertiesSelector ] ( node ) {
88
- if ( reported . has ( node ) || isShadowed ( context . getScope ( ) , node ) ) {
89
- return ;
90
- }
91
-
92
- const { name, parent} = node ;
93
- if ( name === 'Infinity' && ! options . checkInfinity ) {
94
- return ;
95
- }
96
-
97
- let property = name ;
98
- if ( name === 'Infinity' ) {
99
- property = isNegative ( node ) ? 'NEGATIVE_INFINITY' : 'POSITIVE_INFINITY' ;
100
- }
101
-
102
- const problem = {
103
- node,
104
- messageId : PROPERTY_ERROR_MESSAGE_ID ,
105
- data : {
106
- identifier : name ,
107
- property,
108
- } ,
109
- } ;
114
+ * 'Program:exit' ( ) {
115
+ const sourceCode = context . getSourceCode ( ) ;
116
+ const tracker = new ReferenceTracker ( context . getScope ( ) ) ;
110
117
111
- if ( property === 'NEGATIVE_INFINITY' ) {
112
- problem . node = parent ;
113
- problem . data . identifier = '-Infinity' ;
114
- problem . fix = function * ( fixer ) {
115
- yield fixer . replaceText ( parent , 'Number.NEGATIVE_INFINITY' ) ;
116
- yield * fixSpaceAroundKeyword ( fixer , parent , sourceCode ) ;
117
- } ;
118
- } else {
119
- problem . fix = fixer => replaceReferenceIdentifier ( node , `Number.${ property } ` , fixer , sourceCode ) ;
120
- }
121
-
122
- reported . add ( node ) ;
123
- return problem ;
118
+ yield * checkMethods ( { sourceCode, tracker} ) ;
119
+ yield * checkProperties ( { sourceCode, tracker, checkInfinity} ) ;
124
120
} ,
125
121
} ;
126
122
} ;
0 commit comments