(program: TSESTree.Program)
| 303 | } |
| 304 | |
| 305 | function summarizeReactProgram(program: TSESTree.Program): ReactAstSummary { |
| 306 | const components: CodeComponent[] = []; |
| 307 | const builtinHooksUsed = new Set<string>(); |
| 308 | const customHooks = new Set<string>(); |
| 309 | let usesContext = false; |
| 310 | let usesMemoization = false; |
| 311 | let usesSuspense = false; |
| 312 | |
| 313 | walkAst(program, (node, parent) => { |
| 314 | if (node.type === 'CallExpression') { |
| 315 | const calleeName = getCalleeName(node.callee); |
| 316 | if (calleeName && BUILTIN_HOOKS.has(calleeName)) { |
| 317 | builtinHooksUsed.add(calleeName); |
| 318 | } |
| 319 | if (calleeName === 'createContext' || calleeName === 'useContext') { |
| 320 | usesContext = true; |
| 321 | } |
| 322 | if (calleeName === 'memo' || calleeName === 'useMemo' || calleeName === 'useCallback') { |
| 323 | usesMemoization = true; |
| 324 | } |
| 325 | if (calleeName === 'lazy') { |
| 326 | usesSuspense = true; |
| 327 | } |
| 328 | if ( |
| 329 | calleeName === 'createContext' && |
| 330 | parent?.type === 'VariableDeclarator' && |
| 331 | parent.id.type === 'Identifier' |
| 332 | ) { |
| 333 | usesContext = true; |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | if (node.type === 'JSXElement') { |
| 338 | const tagName = getJsxTagName(node.openingElement.name); |
| 339 | if (tagName === 'Suspense' || tagName === 'React.Suspense') { |
| 340 | usesSuspense = true; |
| 341 | } |
| 342 | if (tagName?.endsWith('.Provider') || tagName?.endsWith('.Consumer')) { |
| 343 | usesContext = true; |
| 344 | } |
| 345 | } |
| 346 | |
| 347 | if (node.type === 'FunctionDeclaration' && node.id?.name) { |
| 348 | const name = node.id.name; |
| 349 | if (isCustomHookName(name)) { |
| 350 | customHooks.add(name); |
| 351 | components.push(toComponent(name, node, 'function', 'hook', { reactType: 'custom-hook' })); |
| 352 | } else if (isComponentName(name) && containsJsx(node.body)) { |
| 353 | components.push( |
| 354 | toComponent(name, node, 'function', 'component', { reactType: 'function-component' }) |
| 355 | ); |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | if (node.type === 'VariableDeclarator' && node.id.type === 'Identifier') { |
| 360 | const variableName = node.id.name; |
| 361 | if ( |
| 362 | node.init && |
no test coverage detected