| 2113 | } |
| 2114 | |
| 2115 | static const char *extract_handler_arg(CBMExtractCtx *ctx, TSNode args) { |
| 2116 | uint32_t nc = ts_node_named_child_count(args); |
| 2117 | for (uint32_t ai = HANDLER_START_IDX; ai < nc && ai < MAX_HANDLER_SCAN; ai++) { |
| 2118 | TSNode arg2 = ts_node_named_child(args, ai); |
| 2119 | /* PHP wraps each argument in an `argument` node — unwrap to the value. */ |
| 2120 | if (strcmp(ts_node_type(arg2), "argument") == 0 && ts_node_named_child_count(arg2) > 0) { |
| 2121 | arg2 = ts_node_named_child(arg2, 0); |
| 2122 | } |
| 2123 | const char *ak2 = ts_node_type(arg2); |
| 2124 | /* `name` = PHP bare identifier handler; string = Laravel string handler |
| 2125 | * ('showUsers' or 'Controller@method'). */ |
| 2126 | if (strcmp(ak2, "identifier") == 0 || strcmp(ak2, "member_expression") == 0 || |
| 2127 | strcmp(ak2, "selector_expression") == 0 || strcmp(ak2, "attribute") == 0 || |
| 2128 | strcmp(ak2, "field_expression") == 0 || strcmp(ak2, "name") == 0) { |
| 2129 | return cbm_node_text(ctx->arena, arg2, ctx->source); |
| 2130 | } |
| 2131 | if (is_string_like(ak2)) { |
| 2132 | const char *h = |
| 2133 | normalize_string_handler(ctx->arena, cbm_node_text(ctx->arena, arg2, ctx->source)); |
| 2134 | if (h && h[0]) { |
| 2135 | return h; |
| 2136 | } |
| 2137 | } |
| 2138 | } |
| 2139 | return NULL; |
| 2140 | } |
| 2141 | |
| 2142 | // Extract JSX component refs (uppercase tags) as CALLS edges. |
| 2143 | static void extract_jsx_component_ref(CBMExtractCtx *ctx, TSNode node, const char *kind, |
no test coverage detected