diff --git a/packages/react-devtools-shared/src/__tests__/injectHookVariableNames-test.js b/packages/react-devtools-shared/src/__tests__/injectHookVariableNames-test.js new file mode 100644 index 0000000000000..8c580679b664f --- /dev/null +++ b/packages/react-devtools-shared/src/__tests__/injectHookVariableNames-test.js @@ -0,0 +1,49 @@ +/** + * @flow + */ + +import {parse} from '@babel/parser' +import traverse from '@babel/traverse'; +import {getHookVariableName, getPotentialHookDeclarationsFromAST} from 'react-devtools-shared/src/utils'; + +describe('injectHookVariableNamesFunction', () => { + it('should identify variable names in destructed syntax', async (done) => { + + const jsxCode = ` + const Example = () => { + const [count, setCount] = React.useState(1); + return count; + }; + `; + + const ast = parse(jsxCode, { sourceType: 'unambiguous', plugins: ['jsx', 'typescript']}); + const hookAstNodes = getPotentialHookDeclarationsFromAST(ast); + + // Only one hook node is present in the source code + expect(hookAstNodes).toHaveLength(1); + + const hookName = getHookVariableName(hookAstNodes[0]); + expect(hookName).toBe('count'); + done(); + }); + + it('should identify variable names in direct assignment', async (done) => { + + const jsxCode = ` + const Example = () => { + const count = React.useState(1); + return count; + }; + `; + + const ast = parse(jsxCode, { sourceType: 'unambiguous', plugins: ['jsx', 'typescript']}); + const hookAstNodes = getPotentialHookDeclarationsFromAST(ast); + + // Only one hook node is present in the source code + expect(hookAstNodes).toHaveLength(1); + + const hookName = getHookVariableName(hookAstNodes[0]); + expect(hookName).toBe('count'); + done(); + }); +}); diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index dd9cd743f550f..98308f23b90f2 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -975,7 +975,7 @@ function modifyHooksToAddVariableNames(hookLog: HooksTree, sourceMaps: Downloade return hook; } - // nodesAssociatedWithReactHookASTNode could directly be a used to obtain the hook variable name + // nodesAssociatedWithReactHookASTNode could directly be used to obtain the hook variable name // depending on the type of potentialReactHookASTNode try { const nodesAssociatedWithReactHookASTNode: NodePath[] = getFilteredHookASTNodes(potentialReactHookASTNode, potentialHooksFound, source, potentialHooksOfFile); @@ -1101,7 +1101,7 @@ function isStateOrReducerHook(path: NodePath): boolean { * @param {File} sourceAST * @return {NodePath[]} */ -function getPotentialHookDeclarationsFromAST(sourceAST: File): NodePath[] { +export function getPotentialHookDeclarationsFromAST(sourceAST: File): NodePath[] { const potentialHooksFound: NodePath[] = []; traverse(sourceAST, { enter(path) { @@ -1355,7 +1355,7 @@ function filterMemberWithHookVariableName(hook: NodePath): boolean { * @param {NodePath} hook The AST Node Path for the concerned hook * @return {string} The variable name to be injected */ -function getHookVariableName(hook: NodePath, isCustomHook: boolean = false): string { +export function getHookVariableName(hook: NodePath, isCustomHook: boolean = false): string { const nodeType = hook.node.id.type; switch (nodeType) { case AST_NODE_TYPES.ARRAY_PATTERN: