Skip to content

Commit 7a12707

Browse files
committed
extract ESM/CSJ getRuleInfo into separate functions
1 parent fcfdec0 commit 7a12707

File tree

1 file changed

+84
-80
lines changed

1 file changed

+84
-80
lines changed

lib/utils.js

+84-80
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)