@@ -69,6 +69,8 @@ function isNormalFunctionExpressionReference (node, scopeManager) {
6969 return isNormalFunctionExpression ( definitionNode ) ;
7070}
7171
72+ const INTERESTING_RULE_KEYS = new Set ( [ 'create' , 'meta' ] ) ;
73+
7274/**
7375* Determines whether a node is constructing a RuleTester instance
7476* @param {ASTNode } node The node in question
@@ -83,8 +85,87 @@ function isRuleTesterConstruction (node) {
8385 ) ;
8486}
8587
86- module . exports = {
88+ /**
89+ * Helper for `getRuleInfo`. Handles ESM rules.
90+ */
91+ function getRuleExportsESM ( ast ) {
92+ return ast . body
93+ . filter ( statement => statement . type === 'ExportDefaultDeclaration' )
94+ . map ( statement => statement . declaration )
95+ . reduce ( ( currentExports , node ) => {
96+ if ( node . type === 'ObjectExpression' ) {
97+ return node . properties . reduce ( ( parsedProps , prop ) => {
98+ const keyValue = module . exports . getKeyName ( prop ) ;
99+ if ( INTERESTING_RULE_KEYS . has ( keyValue ) ) {
100+ parsedProps [ keyValue ] = prop . value ;
101+ }
102+ return parsedProps ;
103+ } , { } ) ;
104+ } else if ( isNormalFunctionExpression ( node ) ) {
105+ return { create : node , meta : null , isNewStyle : false } ;
106+ }
107+ return currentExports ;
108+ } , { } ) ;
109+ }
87110
111+ /**
112+ * Helper for `getRuleInfo`. Handles CJS rules.
113+ */
114+ function getRuleExportsCJS ( ast ) {
115+ let exportsVarOverridden = false ;
116+ let exportsIsFunction = false ;
117+ return ast . body
118+ . filter ( statement => statement . type === 'ExpressionStatement' )
119+ . map ( statement => statement . expression )
120+ . filter ( expression => expression . type === 'AssignmentExpression' )
121+ . filter ( expression => expression . left . type === 'MemberExpression' )
122+ . reduce ( ( currentExports , node ) => {
123+ if (
124+ node . left . object . type === 'Identifier' && node . left . object . name === 'module' &&
125+ node . left . property . type === 'Identifier' && node . left . property . name === 'exports'
126+ ) {
127+ exportsVarOverridden = true ;
128+ if ( isNormalFunctionExpression ( node . right ) ) {
129+ // Check `module.exports = function () {}`
130+
131+ exportsIsFunction = true ;
132+ return { create : node . right , meta : null , isNewStyle : false } ;
133+ } else if ( node . right . type === 'ObjectExpression' ) {
134+ // Check `module.exports = { create: function () {}, meta: {} }`
135+
136+ return node . right . properties . reduce ( ( parsedProps , prop ) => {
137+ const keyValue = module . exports . getKeyName ( prop ) ;
138+ if ( INTERESTING_RULE_KEYS . has ( keyValue ) ) {
139+ parsedProps [ keyValue ] = prop . value ;
140+ }
141+ return parsedProps ;
142+ } , { } ) ;
143+ }
144+ return { } ;
145+ } else if (
146+ ! exportsIsFunction &&
147+ node . left . object . type === 'MemberExpression' &&
148+ node . left . object . object . type === 'Identifier' && node . left . object . object . name === 'module' &&
149+ node . left . object . property . type === 'Identifier' && node . left . object . property . name === 'exports' &&
150+ node . left . property . type === 'Identifier' && INTERESTING_RULE_KEYS . has ( node . left . property . name )
151+ ) {
152+ // Check `module.exports.create = () => {}`
153+
154+ currentExports [ node . left . property . name ] = node . right ;
155+ } else if (
156+ ! exportsVarOverridden &&
157+ node . left . object . type === 'Identifier' && node . left . object . name === 'exports' &&
158+ node . left . property . type === 'Identifier' && INTERESTING_RULE_KEYS . has ( node . left . property . name )
159+ ) {
160+ // Check `exports.create = () => {}`
161+
162+ currentExports [ node . left . property . name ] = node . right ;
163+ }
164+ return currentExports ;
165+ } , { } ) ;
166+ }
167+
168+ module . exports = {
88169 /**
89170 * Performs static analysis on an AST to try to determine the final value of `module.exports`.
90171 * @param {{ast: ASTNode, scopeManager?: ScopeManager} } sourceCode The object contains `Program` AST node, and optional `scopeManager`
@@ -94,84 +175,7 @@ module.exports = {
94175 from the file, the return value will be `null`.
95176 */
96177 getRuleInfo ( { ast, scopeManager } ) {
97- const INTERESTING_KEYS = new Set ( [ 'create' , 'meta' ] ) ;
98- let exportsVarOverridden = false ;
99- let exportsIsFunction = false ;
100-
101- // ESM
102- const exportNodesESM = ast . body
103- . filter ( statement => statement . type === 'ExportDefaultDeclaration' )
104- . map ( statement => statement . declaration )
105- . reduce ( ( currentExports , node ) => {
106- if ( node . type === 'ObjectExpression' ) {
107- return node . properties . reduce ( ( parsedProps , prop ) => {
108- const keyValue = module . exports . getKeyName ( prop ) ;
109- if ( INTERESTING_KEYS . has ( keyValue ) ) {
110- parsedProps [ keyValue ] = prop . value ;
111- }
112- return parsedProps ;
113- } , { } ) ;
114- } else if ( isNormalFunctionExpression ( node ) ) {
115- exportsIsFunction = true ;
116- return { create : node , meta : null } ;
117- }
118- return currentExports ;
119- } , null ) ;
120-
121- // CJS
122- const exportNodesCJS = ast . body
123- . filter ( statement => statement . type === 'ExpressionStatement' )
124- . map ( statement => statement . expression )
125- . filter ( expression => expression . type === 'AssignmentExpression' )
126- . filter ( expression => expression . left . type === 'MemberExpression' )
127- . reduce ( ( currentExports , node ) => {
128- if (
129- node . left . object . type === 'Identifier' && node . left . object . name === 'module' &&
130- node . left . property . type === 'Identifier' && node . left . property . name === 'exports'
131- ) {
132- exportsVarOverridden = true ;
133-
134- if ( isNormalFunctionExpression ( node . right ) ) {
135- // Check `module.exports = function () {}`
136-
137- exportsIsFunction = true ;
138- return { create : node . right , meta : null } ;
139- } else if ( node . right . type === 'ObjectExpression' ) {
140- // Check `module.exports = { create: function () {}, meta: {} }`
141-
142- exportsIsFunction = false ;
143- return node . right . properties . reduce ( ( parsedProps , prop ) => {
144- const keyValue = module . exports . getKeyName ( prop ) ;
145- if ( INTERESTING_KEYS . has ( keyValue ) ) {
146- parsedProps [ keyValue ] = prop . value ;
147- }
148- return parsedProps ;
149- } , { } ) ;
150- }
151- return { } ;
152- } else if (
153- ! exportsIsFunction &&
154- node . left . object . type === 'MemberExpression' &&
155- node . left . object . object . type === 'Identifier' && node . left . object . object . name === 'module' &&
156- node . left . object . property . type === 'Identifier' && node . left . object . property . name === 'exports' &&
157- node . left . property . type === 'Identifier' && INTERESTING_KEYS . has ( node . left . property . name )
158- ) {
159- // Check `module.exports.create = () => {}`
160-
161- currentExports [ node . left . property . name ] = node . right ;
162- } else if (
163- ! exportsVarOverridden &&
164- node . left . object . type === 'Identifier' && node . left . object . name === 'exports' &&
165- node . left . property . type === 'Identifier' && INTERESTING_KEYS . has ( node . left . property . name )
166- ) {
167- // Check `exports.create = () => {}`
168-
169- currentExports [ node . left . property . name ] = node . right ;
170- }
171- return currentExports ;
172- } , { } ) ;
173-
174- const exportNodes = exportNodesESM || exportNodesCJS ;
178+ const exportNodes = ast . sourceType === 'module' ? getRuleExportsESM ( ast ) : getRuleExportsCJS ( ast ) ;
175179
176180 const createExists = Object . prototype . hasOwnProperty . call ( exportNodes , 'create' ) ;
177181 if ( ! createExists ) {
@@ -185,7 +189,7 @@ module.exports = {
185189 return null ;
186190 }
187191
188- return Object . assign ( { isNewStyle : ! exportsIsFunction , meta : null } , exportNodes ) ;
192+ return Object . assign ( { isNewStyle : true , meta : null } , exportNodes ) ;
189193 } ,
190194
191195 /**
0 commit comments