| 1578 | } |
| 1579 | |
| 1580 | static const char *extract_handler_arg(CBMExtractCtx *ctx, TSNode args) { |
| 1581 | uint32_t nc = ts_node_named_child_count(args); |
| 1582 | for (uint32_t ai = HANDLER_START_IDX; ai < nc && ai < MAX_HANDLER_SCAN; ai++) { |
| 1583 | TSNode arg2 = ts_node_named_child(args, ai); |
| 1584 | /* PHP wraps each argument in an `argument` node — unwrap to the value. */ |
| 1585 | if (strcmp(ts_node_type(arg2), "argument") == 0 && ts_node_named_child_count(arg2) > 0) { |
| 1586 | arg2 = ts_node_named_child(arg2, 0); |
| 1587 | } |
| 1588 | const char *ak2 = ts_node_type(arg2); |
| 1589 | /* `name` = PHP bare identifier handler; string = Laravel string handler |
| 1590 | * ('showUsers' or 'Controller@method'). */ |
| 1591 | if (strcmp(ak2, "identifier") == 0 || strcmp(ak2, "member_expression") == 0 || |
| 1592 | strcmp(ak2, "selector_expression") == 0 || strcmp(ak2, "attribute") == 0 || |
| 1593 | strcmp(ak2, "field_expression") == 0 || strcmp(ak2, "name") == 0) { |
| 1594 | return cbm_node_text(ctx->arena, arg2, ctx->source); |
| 1595 | } |
| 1596 | if (is_string_like(ak2)) { |
| 1597 | const char *h = |
| 1598 | normalize_string_handler(ctx->arena, cbm_node_text(ctx->arena, arg2, ctx->source)); |
| 1599 | if (h && h[0]) { |
| 1600 | return h; |
| 1601 | } |
| 1602 | } |
| 1603 | } |
| 1604 | return NULL; |
| 1605 | } |
| 1606 | |
| 1607 | // Extract JSX component refs (uppercase tags) as CALLS edges. |
| 1608 | static void extract_jsx_component_ref(CBMExtractCtx *ctx, TSNode node, const char *kind, |
no test coverage detected