10
10
11
11
const path = require ( 'path' ) ;
12
12
const util = require ( '../utils' ) ;
13
+ const { getStaticValue } = require ( 'eslint-utils' ) ;
13
14
14
15
// -----------------------------------------------------------------------------
15
16
// Rule Definition
@@ -31,6 +32,11 @@ module.exports = {
31
32
} ,
32
33
additionalProperties : false ,
33
34
} ] ,
35
+ messages : {
36
+ mismatch : '`meta.docs.url` property must be `{{expectedUrl}}`.' ,
37
+ missing : 'Rules should export a `meta.docs.url` property.' ,
38
+ wrongType : '`meta.docs.url` property must be a string.' ,
39
+ } ,
34
40
} ,
35
41
36
42
/**
@@ -48,24 +54,22 @@ module.exports = {
48
54
: options . pattern . replace ( / { { \s * n a m e \s * } } / g, ruleName ) ;
49
55
50
56
/**
51
- * Check whether a given node is the expected URL.
52
- * @param {Node } node The node of property value to check.
57
+ * Check whether a given URL is the expected URL.
58
+ * @param {String } url The URL to check.
53
59
* @returns {boolean } `true` if the node is the expected URL.
54
60
*/
55
- function isExpectedUrl ( node ) {
61
+ function isExpectedUrl ( url ) {
56
62
return Boolean (
57
- node &&
58
- node . type === 'Literal' &&
59
- typeof node . value === 'string' &&
63
+ typeof url === 'string' &&
60
64
(
61
65
expectedUrl === undefined ||
62
- node . value === expectedUrl
66
+ url === expectedUrl
63
67
)
64
68
) ;
65
69
}
66
70
67
71
return {
68
- Program ( node ) {
72
+ Program ( ) {
69
73
const info = util . getRuleInfo ( sourceCode ) ;
70
74
if ( info === null ) {
71
75
return ;
@@ -81,40 +85,45 @@ module.exports = {
81
85
docsPropNode . value . properties &&
82
86
docsPropNode . value . properties . find ( p => p . type === 'Property' && util . getKeyName ( p ) === 'url' ) ;
83
87
84
- if ( isExpectedUrl ( urlPropNode && urlPropNode . value ) ) {
88
+ const staticValue = urlPropNode ? getStaticValue ( urlPropNode . value , context . getScope ( ) ) : undefined ;
89
+ if ( urlPropNode && ! staticValue ) {
90
+ // Ignore non-static values since we can't determine what they look like.
91
+ return ;
92
+ }
93
+
94
+ if ( isExpectedUrl ( staticValue && staticValue . value ) ) {
85
95
return ;
86
96
}
87
97
88
98
context . report ( {
89
- loc :
90
- ( urlPropNode && urlPropNode . value . loc ) ||
91
- ( docsPropNode && docsPropNode . value . loc ) ||
92
- ( metaNode && metaNode . loc ) ||
93
- node . loc . start ,
94
-
95
- message :
96
- ! urlPropNode ? 'Rules should export a `meta.docs.url` property.' :
99
+ node : ( urlPropNode && urlPropNode . value ) || ( docsPropNode && docsPropNode . value ) || metaNode || info . create ,
100
+
101
+ messageId :
102
+ ! urlPropNode ? 'missing' :
97
103
// eslint-disable-next-line unicorn/no-nested-ternary
98
- ! expectedUrl ? '`meta.docs.url` property must be a string. ' :
99
- /* otherwise */ '`meta.docs.url` property must be `{{expectedUrl}}`. ' ,
104
+ ! expectedUrl ? 'wrongType ' :
105
+ /* otherwise */ 'mismatch ' ,
100
106
101
107
data : {
102
108
expectedUrl,
103
109
} ,
104
110
105
111
fix ( fixer ) {
106
- if ( expectedUrl ) {
107
- const urlString = JSON . stringify ( expectedUrl ) ;
108
- if ( urlPropNode ) {
112
+ if ( ! expectedUrl ) {
113
+ return null ;
114
+ }
115
+
116
+ const urlString = JSON . stringify ( expectedUrl ) ;
117
+ if ( urlPropNode ) {
118
+ if ( urlPropNode . value . type === 'Literal' || ( urlPropNode . value . type === 'Identifier' && urlPropNode . value . name === 'undefined' ) ) {
109
119
return fixer . replaceText ( urlPropNode . value , urlString ) ;
110
120
}
111
- if ( docsPropNode && docsPropNode . value . type === 'ObjectExpression' ) {
112
- return util . insertProperty ( fixer , docsPropNode . value , `url: ${ urlString } ` , sourceCode ) ;
113
- }
114
- if ( ! docsPropNode && metaNode && metaNode . type === 'ObjectExpression' ) {
115
- return util . insertProperty ( fixer , metaNode , `docs: {\nurl: ${ urlString } \n}` , sourceCode ) ;
116
- }
121
+ } else if ( docsPropNode && docsPropNode . value . type === 'ObjectExpression' ) {
122
+ return util . insertProperty ( fixer , docsPropNode . value , `url: ${ urlString } ` , sourceCode ) ;
123
+ } else if ( ! docsPropNode && metaNode && metaNode . type === 'ObjectExpression' ) {
124
+ return util . insertProperty ( fixer , metaNode , `docs: {\nurl: ${ urlString } \n}` , sourceCode ) ;
117
125
}
126
+
118
127
return null ;
119
128
} ,
120
129
} ) ;
0 commit comments