| 813 | * ══════════════════════════════════════════════════════════════════ */ |
| 814 | |
| 815 | static void ruby_process_call(CBMExtractCtx *ctx, TSNode call) { |
| 816 | const char *kind = ts_node_type(call); |
| 817 | TSNode method_node; |
| 818 | |
| 819 | if (strcmp(kind, "call") == 0) { |
| 820 | method_node = ts_node_child_by_field_name(call, TS_FIELD("method")); |
| 821 | } else { |
| 822 | return; |
| 823 | } |
| 824 | |
| 825 | if (ts_node_is_null(method_node)) { |
| 826 | return; |
| 827 | } |
| 828 | char *method = cbm_node_text(ctx->arena, method_node, ctx->source); |
| 829 | if (!method) { |
| 830 | return; |
| 831 | } |
| 832 | |
| 833 | /* ActionCable.server.broadcast("channel", data) */ |
| 834 | if (strcmp(method, "broadcast") == 0) { |
| 835 | TSNode args = ts_node_child_by_field_name(call, TS_FIELD("arguments")); |
| 836 | if (!ts_node_is_null(args)) { |
| 837 | const char *channel_name = extract_channel_name(ctx, args, NULL); |
| 838 | if (channel_name) { |
| 839 | push_channel(ctx, channel_name, "actioncable", CBM_CHANNEL_EMIT, call); |
| 840 | } |
| 841 | } |
| 842 | return; |
| 843 | } |
| 844 | |
| 845 | /* stream_from "channel" — listener registration */ |
| 846 | if (strcmp(method, "stream_from") == 0 || strcmp(method, "stream_for") == 0) { |
| 847 | TSNode args = ts_node_child_by_field_name(call, TS_FIELD("arguments")); |
| 848 | if (!ts_node_is_null(args)) { |
| 849 | const char *channel_name = extract_channel_name(ctx, args, NULL); |
| 850 | if (channel_name) { |
| 851 | push_channel(ctx, channel_name, "actioncable", CBM_CHANNEL_LISTEN, call); |
| 852 | } |
| 853 | } |
| 854 | } |
| 855 | } |
| 856 | |
| 857 | static void extract_channels_ruby(CBMExtractCtx *ctx) { |
| 858 | TSNodeStack stack; |
no test coverage detected