| 2089 | } |
| 2090 | |
| 2091 | static const char *extract_handler_arg(CBMExtractCtx *ctx, TSNode args) { |
| 2092 | uint32_t nc = ts_node_named_child_count(args); |
| 2093 | for (uint32_t ai = HANDLER_START_IDX; ai < nc && ai < MAX_HANDLER_SCAN; ai++) { |
| 2094 | TSNode arg2 = ts_node_named_child(args, ai); |
| 2095 | /* PHP wraps each argument in an `argument` node — unwrap to the value. */ |
| 2096 | if (strcmp(ts_node_type(arg2), "argument") == 0 && ts_node_named_child_count(arg2) > 0) { |
| 2097 | arg2 = ts_node_named_child(arg2, 0); |
| 2098 | } |
| 2099 | const char *ak2 = ts_node_type(arg2); |
| 2100 | /* `name` = PHP bare identifier handler; string = Laravel string handler |
| 2101 | * ('showUsers' or 'Controller@method'). */ |
| 2102 | if (strcmp(ak2, "identifier") == 0 || strcmp(ak2, "member_expression") == 0 || |
| 2103 | strcmp(ak2, "selector_expression") == 0 || strcmp(ak2, "attribute") == 0 || |
| 2104 | strcmp(ak2, "field_expression") == 0 || strcmp(ak2, "name") == 0) { |
| 2105 | return cbm_node_text(ctx->arena, arg2, ctx->source); |
| 2106 | } |
| 2107 | if (is_string_like(ak2)) { |
| 2108 | const char *h = |
| 2109 | normalize_string_handler(ctx->arena, cbm_node_text(ctx->arena, arg2, ctx->source)); |
| 2110 | if (h && h[0]) { |
| 2111 | return h; |
| 2112 | } |
| 2113 | } |
| 2114 | } |
| 2115 | return NULL; |
| 2116 | } |
| 2117 | |
| 2118 | // Extract JSX component refs (uppercase tags) as CALLS edges. |
| 2119 | static void extract_jsx_component_ref(CBMExtractCtx *ctx, TSNode node, const char *kind, |
no test coverage detected