* Detect a React component declared via an HOC wrapper whose result is itself a * component: `forwardRef(...)`, `memo(...)`, `React.forwardRef/memo(...)`, and * styled-components / emotion `styled.tag\`…\`` / `styled(Base)\`…\``. These * initializers are a call / tagged-template (not a bare
(valueNode: SyntaxNode)
| 1496 | * `undefined` when this initializer is not a recognized component wrapper. |
| 1497 | */ |
| 1498 | private reactComponentHoc(valueNode: SyntaxNode): { inner: SyntaxNode | null } | undefined { |
| 1499 | if (valueNode.type !== 'call_expression') return undefined; |
| 1500 | const callee = getChildByField(valueNode, 'function'); |
| 1501 | if (!callee) return undefined; |
| 1502 | const calleeText = getNodeText(callee, this.source); |
| 1503 | // styled-components / emotion: `styled.button\`…\`` / `styled(Base)\`…\``. |
| 1504 | // tree-sitter models these tagged templates as a call_expression whose callee |
| 1505 | // is the `styled.x` / `styled(Base)` tag (\b avoids matching `styledFoo`). |
| 1506 | // No inline render fn — the argument is the CSS template. |
| 1507 | if (/^styled\b/.test(calleeText)) return { inner: null }; |
| 1508 | // React HOCs: `forwardRef`/`memo`/`React.forwardRef`/`React.memo`. |
| 1509 | if (!REACT_COMPONENT_HOCS.has(calleeText)) return undefined; |
| 1510 | // The first arrow / function-expression argument is the render fn (if inline; |
| 1511 | // `memo(Imported)` passes a bare identifier and has none). |
| 1512 | const args = getChildByField(valueNode, 'arguments'); |
| 1513 | let inner: SyntaxNode | null = null; |
| 1514 | if (args) { |
| 1515 | for (let i = 0; i < args.namedChildCount; i++) { |
| 1516 | const a = args.namedChild(i); |
| 1517 | if (a && (a.type === 'arrow_function' || a.type === 'function_expression')) { |
| 1518 | inner = a; |
| 1519 | break; |
| 1520 | } |
| 1521 | } |
| 1522 | } |
| 1523 | return { inner }; |
| 1524 | } |
| 1525 | |
| 1526 | /** |
| 1527 | * Emit a `component` node for an HOC-wrapped React component declaration (see |
no test coverage detected