Skip to content

Commit

Permalink
[Test] Component util isReactHookCall
Browse files Browse the repository at this point in the history
Rename Components test suite filename to match sibling lib/util/Components filename.
Extend Components testComponentsDetect function to accept custom instructions, and to accumulate the results of processing those instructions.
Add utility to check whether a CallExpression is a React hook call.
  • Loading branch information
duncanbeevers committed Dec 13, 2021
1 parent ac4e311 commit 8232873
Show file tree
Hide file tree
Showing 3 changed files with 290 additions and 98 deletions.
71 changes: 71 additions & 0 deletions lib/util/Components.js
Expand Up @@ -46,6 +46,8 @@ function mergeUsedPropTypes(propsList, newPropsList) {
return propsList.concat(propsToAdd);
}

const USE_HOOK_PREFIX_REGEX = /^use/i;

const Lists = new WeakMap();
const ReactImports = new WeakMap();

Expand Down Expand Up @@ -787,6 +789,75 @@ function componentRule(rule, context) {
&& !!(node.params || []).length
);
},

isReactHookCall(node, expectedHookNames) {
if (node.type !== 'CallExpression') {
return false;
}

const defaultReactImports = components.getDefaultReactImports();
const namedReactImports = components.getNamedReactImports();

const defaultReactImportSpecifier = defaultReactImports
? defaultReactImports[0]
: undefined;

const defaultReactImportName = defaultReactImportSpecifier
? defaultReactImportSpecifier.local.name
: undefined;

const reactHookImportSpecifiers = namedReactImports
? namedReactImports.filter((specifier) => specifier.imported.name.match(USE_HOOK_PREFIX_REGEX))
: undefined;
const reactHookImportNames = reactHookImportSpecifiers
? reactHookImportSpecifiers.map((specifier) => specifier.local.name)
: undefined;

const isPotentialReactHookCall = !!(
defaultReactImportName
&& node.callee.type === 'MemberExpression'
&& node.callee.object.type === 'Identifier'
&& node.callee.object.name === defaultReactImportName
&& node.callee.property.type === 'Identifier'
&& node.callee.property.name.match(USE_HOOK_PREFIX_REGEX)
);

const isPotentialHookCall = !!(
reactHookImportNames
&& node.callee.type === 'Identifier'
&& node.callee.name.match(USE_HOOK_PREFIX_REGEX)
);

const scope = isPotentialReactHookCall || isPotentialHookCall
? context.getScope()
: undefined;

const reactResolvedDefs = isPotentialReactHookCall && scope.references.find(
(reference) => reference.identifier.name === defaultReactImportName
).resolved.defs;
const hookResolvedDefs = isPotentialHookCall && scope.references.find(
(reference) => reactHookImportNames.includes(reference.identifier.name)
).resolved.defs;

const hookName = (isPotentialReactHookCall && node.callee.property.name)
|| (isPotentialHookCall && node.callee.name);

const isReactShadowed = isPotentialReactHookCall && reactResolvedDefs
&& reactResolvedDefs.some((reactDef) => reactDef.type !== 'ImportBinding');

const isHookShadowed = isPotentialHookCall
&& hookResolvedDefs
&& hookResolvedDefs.some(
(hookDef) => hookDef.name.name === hookName
&& hookDef.type !== 'ImportBinding'
);

const isHookCall = (isPotentialReactHookCall && !isReactShadowed)
|| (isPotentialHookCall && !isHookShadowed);

return isHookCall
&& (!expectedHookNames || expectedHookNames.includes(hookName));
},
};

// Component detection instructions
Expand Down
98 changes: 0 additions & 98 deletions tests/util/Component.js

This file was deleted.

0 comments on commit 8232873

Please sign in to comment.