@@ -82,10 +82,32 @@ function isFunctionRule (node) {
82
82
) ;
83
83
}
84
84
85
+ /**
86
+ * Check if the given node is a function call representing a known TypeScript rule creator format.
87
+ * @param {Node } node
88
+ * @returns {boolean }
89
+ */
90
+ function isTypeScriptRuleHelper ( node ) {
91
+ return (
92
+ node . type === 'CallExpression' &&
93
+ node . arguments . length === 1 &&
94
+ node . arguments [ 0 ] . type === 'ObjectExpression' &&
95
+ // Check various TypeScript rule helper formats.
96
+ (
97
+ // createESLintRule({ ... })
98
+ node . callee . type === 'Identifier' ||
99
+ // util.createRule({ ... })
100
+ ( node . callee . type === 'MemberExpression' && node . callee . object . type === 'Identifier' && node . callee . property . type === 'Identifier' ) ||
101
+ // ESLintUtils.RuleCreator(docsUrl)({ ... })
102
+ ( node . callee . type === 'CallExpression' && node . callee . callee . type === 'MemberExpression' && node . callee . callee . object . type === 'Identifier' && node . callee . callee . property . type === 'Identifier' )
103
+ )
104
+ ) ;
105
+ }
106
+
85
107
/**
86
108
* Helper for `getRuleInfo`. Handles ESM and TypeScript rules.
87
109
*/
88
- function getRuleExportsESM ( ast ) {
110
+ function getRuleExportsESM ( ast , scopeManager ) {
89
111
return ast . body
90
112
. filter ( statement => statement . type === 'ExportDefaultDeclaration' )
91
113
. map ( statement => statement . declaration )
@@ -97,22 +119,20 @@ function getRuleExportsESM (ast) {
97
119
} else if ( isFunctionRule ( node ) ) {
98
120
// Check `export default function(context) { return { ... }; }`
99
121
return { create : node , meta : null , isNewStyle : false } ;
100
- } else if (
101
- node . type === 'CallExpression' &&
102
- node . arguments . length === 1 &&
103
- node . arguments [ 0 ] . type === 'ObjectExpression' &&
104
- // Check various TypeScript rule helper formats.
105
- (
106
- // createESLintRule({ ... })
107
- node . callee . type === 'Identifier' ||
108
- // util.createRule({ ... })
109
- ( node . callee . type === 'MemberExpression' && node . callee . object . type === 'Identifier' && node . callee . property . type === 'Identifier' ) ||
110
- // ESLintUtils.RuleCreator(docsUrl)({ ... })
111
- ( node . callee . type === 'CallExpression' && node . callee . callee . type === 'MemberExpression' && node . callee . callee . object . type === 'Identifier' && node . callee . callee . property . type === 'Identifier' )
112
- )
113
- ) {
122
+ } else if ( isTypeScriptRuleHelper ( node ) ) {
114
123
// Check `export default someTypeScriptHelper({ create() {}, meta: {} });
115
124
return collectInterestingProperties ( node . arguments [ 0 ] . properties , INTERESTING_RULE_KEYS ) ;
125
+ } else if ( node . type === 'Identifier' ) {
126
+ const possibleRule = findVariableValue ( node , scopeManager ) ;
127
+ if ( possibleRule ) {
128
+ if ( possibleRule . type === 'ObjectExpression' ) {
129
+ // Check `const possibleRule = { ... }; export default possibleRule;
130
+ return collectInterestingProperties ( possibleRule . properties , INTERESTING_RULE_KEYS ) ;
131
+ } else if ( isTypeScriptRuleHelper ( possibleRule ) ) {
132
+ // Check `const possibleRule = someTypeScriptHelper({ ... }); export default possibleRule;
133
+ return collectInterestingProperties ( possibleRule . arguments [ 0 ] . properties , INTERESTING_RULE_KEYS ) ;
134
+ }
135
+ }
116
136
}
117
137
return currentExports ;
118
138
} , { } ) ;
@@ -121,7 +141,7 @@ function getRuleExportsESM (ast) {
121
141
/**
122
142
* Helper for `getRuleInfo`. Handles CJS rules.
123
143
*/
124
- function getRuleExportsCJS ( ast ) {
144
+ function getRuleExportsCJS ( ast , scopeManager ) {
125
145
let exportsVarOverridden = false ;
126
146
let exportsIsFunction = false ;
127
147
return ast . body
@@ -145,6 +165,12 @@ function getRuleExportsCJS (ast) {
145
165
// Check `module.exports = { create: function () {}, meta: {} }`
146
166
147
167
return collectInterestingProperties ( node . right . properties , INTERESTING_RULE_KEYS ) ;
168
+ } else if ( node . right . type === 'Identifier' ) {
169
+ const possibleRule = findVariableValue ( node . right , scopeManager ) ;
170
+ if ( possibleRule && possibleRule . type === 'ObjectExpression' ) {
171
+ // Check `const possibleRule = { ... }; module.exports = possibleRule;
172
+ return collectInterestingProperties ( possibleRule . properties , INTERESTING_RULE_KEYS ) ;
173
+ }
148
174
}
149
175
return { } ;
150
176
} else if (
@@ -218,7 +244,7 @@ module.exports = {
218
244
from the file, the return value will be `null`.
219
245
*/
220
246
getRuleInfo ( { ast, scopeManager } ) {
221
- const exportNodes = ast . sourceType === 'module' ? getRuleExportsESM ( ast ) : getRuleExportsCJS ( ast ) ;
247
+ const exportNodes = ast . sourceType === 'module' ? getRuleExportsESM ( ast , scopeManager ) : getRuleExportsCJS ( ast , scopeManager ) ;
222
248
223
249
const createExists = Object . prototype . hasOwnProperty . call ( exportNodes , 'create' ) ;
224
250
if ( ! createExists ) {
0 commit comments