Skip to content

Commit 013b2a5

Browse files
committed
Add utility function to infer ramda method name
1 parent bed8196 commit 013b2a5

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

lib/utils.js

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
'use strict';
2+
3+
const R = require('ramda');
4+
5+
const getPropertyName = R.pipe(R.prop('property'), R.either(R.prop('name'), R.prop('value')));
6+
7+
const isIdentifierEqualsToReference = R.curry((identifierNode, reference) => {
8+
return R.equals(reference.identifier, identifierNode);
9+
});
10+
11+
const isTypeOf = R.propEq('type');
12+
const isCallExpression = isTypeOf('CallExpression');
13+
const isIdentifier = isTypeOf('Identifier');
14+
const isMemberExpression = isTypeOf('MemberExpression');
15+
16+
function findReference(scope, node) {
17+
const findReferenceByRange = R.find(isIdentifierEqualsToReference(node));
18+
return findReferenceByRange(scope.references);
19+
}
20+
21+
function isStaticRequireCallOf(node, module) {
22+
const callee = node.callee;
23+
const firstArgument = R.head(node.arguments);
24+
25+
return callee.name === 'require' &&
26+
node.arguments.length === 1 &&
27+
firstArgument.type === 'Literal' &&
28+
firstArgument.value === module;
29+
}
30+
31+
function isImportSourceOf(node, module) {
32+
return node.source.value === module;
33+
}
34+
35+
function hasAlias(importSpecifierNode) {
36+
return importSpecifierNode.imported.name !== importSpecifierNode.local.name;
37+
}
38+
39+
function isResolved(reference) {
40+
return reference && Boolean(reference.resolved);
41+
}
42+
43+
function isResolvedToRamda(scope, reference) {
44+
if (!isResolved(reference)) {
45+
return false;
46+
}
47+
48+
const lastDefinition = R.last(reference.resolved.defs);
49+
50+
if (lastDefinition.node.type === 'VariableDeclarator' && lastDefinition.node.init) {
51+
if (isCallExpression(lastDefinition.node.init)) {
52+
return isStaticRequireCallOf(lastDefinition.node.init, 'ramda');
53+
} else if (lastDefinition.node.init.type === 'Identifier') {
54+
const ref = findReference(scope, lastDefinition.node.init);
55+
return isResolvedToRamda(scope, ref);
56+
}
57+
} else if (lastDefinition.node.type === 'ImportSpecifier') {
58+
if (!hasAlias(lastDefinition.node)) {
59+
return isImportSourceOf(lastDefinition.node.parent, 'ramda');
60+
}
61+
} else if (lastDefinition.node.type === 'ImportDefaultSpecifier') {
62+
return isImportSourceOf(lastDefinition.node.parent, 'ramda');
63+
}
64+
65+
return false;
66+
}
67+
68+
function isGlobalReference(scope, node) {
69+
const name = node.name;
70+
71+
if (node.type === "Identifier" && (name === 'window' || name === 'global')) {
72+
const ref = findReference(scope, node);
73+
return !isResolved(ref);
74+
}
75+
76+
return false;
77+
}
78+
79+
const isRamdaMethod = R.curry((methodName, scope, callee) => {
80+
if (isMemberExpression(callee)) {
81+
const object = callee.object;
82+
const possibleRamdaMethodName = getPropertyName(callee);
83+
84+
if (possibleRamdaMethodName === methodName) {
85+
if (isIdentifier(object) || (isMemberExpression(object) && isGlobalReference(scope, object.object))) {
86+
const reference = findReference(scope, object);
87+
88+
return isResolvedToRamda(scope, reference) || !isResolved(reference);
89+
}
90+
}
91+
}
92+
93+
if (callee.type === 'Identifier') {
94+
const reference = findReference(scope, callee);
95+
return isResolvedToRamda(scope, reference);
96+
}
97+
98+
return false;
99+
});
100+
101+
const isRamdaFilterCall = R.propSatisfies(isRamdaMethod('filter'), 'callee');
102+
103+
module.exports = {
104+
isRamdaMethod,
105+
isCallExpression
106+
};

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"files": [
4343
"index.js",
4444
"rules/",
45+
"lib/",
4546
"LICENSE",
4647
"README.md"
4748
]

0 commit comments

Comments
 (0)