@@ -82,10 +82,32 @@ function isFunctionRule (node) {
8282 ) ;
8383}
8484
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+
85107/**
86108 * Helper for `getRuleInfo`. Handles ESM and TypeScript rules.
87109 */
88- function getRuleExportsESM ( ast ) {
110+ function getRuleExportsESM ( ast , scopeManager ) {
89111 return ast . body
90112 . filter ( statement => statement . type === 'ExportDefaultDeclaration' )
91113 . map ( statement => statement . declaration )
@@ -97,22 +119,20 @@ function getRuleExportsESM (ast) {
97119 } else if ( isFunctionRule ( node ) ) {
98120 // Check `export default function(context) { return { ... }; }`
99121 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 ) ) {
114123 // Check `export default someTypeScriptHelper({ create() {}, meta: {} });
115124 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+ }
116136 }
117137 return currentExports ;
118138 } , { } ) ;
@@ -121,7 +141,7 @@ function getRuleExportsESM (ast) {
121141/**
122142 * Helper for `getRuleInfo`. Handles CJS rules.
123143 */
124- function getRuleExportsCJS ( ast ) {
144+ function getRuleExportsCJS ( ast , scopeManager ) {
125145 let exportsVarOverridden = false ;
126146 let exportsIsFunction = false ;
127147 return ast . body
@@ -145,6 +165,12 @@ function getRuleExportsCJS (ast) {
145165 // Check `module.exports = { create: function () {}, meta: {} }`
146166
147167 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+ }
148174 }
149175 return { } ;
150176 } else if (
@@ -218,7 +244,7 @@ module.exports = {
218244 from the file, the return value will be `null`.
219245 */
220246 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 ) ;
222248
223249 const createExists = Object . prototype . hasOwnProperty . call ( exportNodes , 'create' ) ;
224250 if ( ! createExists ) {
0 commit comments