| 747 | * ══════════════════════════════════════════════════════════════════ */ |
| 748 | |
| 749 | static void csharp_process_call(CBMExtractCtx *ctx, TSNode call) { |
| 750 | TSNode func = ts_node_child_by_field_name(call, TS_FIELD("function")); |
| 751 | if (ts_node_is_null(func)) { |
| 752 | return; |
| 753 | } |
| 754 | const char *fk = ts_node_type(func); |
| 755 | if (strcmp(fk, "member_access_expression") != 0) { |
| 756 | return; |
| 757 | } |
| 758 | TSNode name_node = ts_node_child_by_field_name(func, TS_FIELD("name")); |
| 759 | if (ts_node_is_null(name_node)) { |
| 760 | return; |
| 761 | } |
| 762 | char *method = cbm_node_text(ctx->arena, name_node, ctx->source); |
| 763 | if (!method) { |
| 764 | return; |
| 765 | } |
| 766 | |
| 767 | /* SignalR: Clients.All.SendAsync("method", data) */ |
| 768 | if (strcmp(method, "SendAsync") == 0 || strcmp(method, "SendCoreAsync") == 0) { |
| 769 | char *full = cbm_node_text(ctx->arena, func, ctx->source); |
| 770 | if (full && (strstr(full, "Clients") || strstr(full, "clients"))) { |
| 771 | TSNode args = ts_node_child_by_field_name(call, TS_FIELD("arguments")); |
| 772 | if (!ts_node_is_null(args)) { |
| 773 | const char *channel_name = extract_channel_name(ctx, args, NULL); |
| 774 | if (channel_name) { |
| 775 | push_channel(ctx, channel_name, "signalr", CBM_CHANNEL_EMIT, call); |
| 776 | } |
| 777 | } |
| 778 | } |
| 779 | return; |
| 780 | } |
| 781 | |
| 782 | /* SignalR: connection.On<T>("method", handler) */ |
| 783 | if (strcmp(method, "On") == 0) { |
| 784 | TSNode args = ts_node_child_by_field_name(call, TS_FIELD("arguments")); |
| 785 | if (!ts_node_is_null(args)) { |
| 786 | const char *channel_name = extract_channel_name(ctx, args, NULL); |
| 787 | if (channel_name) { |
| 788 | push_channel(ctx, channel_name, "signalr", CBM_CHANNEL_LISTEN, call); |
| 789 | } |
| 790 | } |
| 791 | } |
| 792 | } |
| 793 | |
| 794 | static void extract_channels_csharp(CBMExtractCtx *ctx) { |
| 795 | TSNodeStack stack; |
no test coverage detected