| 1036 | } |
| 1037 | |
| 1038 | static void handle_string_refs(CBMExtractCtx *ctx, TSNode node, const WalkState *state) { |
| 1039 | const char *kind = ts_node_type(node); |
| 1040 | /* JS/TS template literals: flatten ${...} substitutions to "{}" so URL-ish |
| 1041 | * template strings become string_refs with the canonical placeholder shape |
| 1042 | * shared with server route paths (issue #1006). */ |
| 1043 | if (strcmp(kind, "template_string") == 0) { |
| 1044 | const char *flat = cbm_template_string_text(ctx->arena, node, ctx->source); |
| 1045 | if (!flat) { |
| 1046 | return; |
| 1047 | } |
| 1048 | int kind_val = cbm_classify_string(flat, (int)strlen(flat)); |
| 1049 | if (kind_val < 0) { |
| 1050 | return; |
| 1051 | } |
| 1052 | CBMStringRef ref = { |
| 1053 | .value = flat, |
| 1054 | .enclosing_func_qn = |
| 1055 | state->enclosing_func_qn ? state->enclosing_func_qn : ctx->module_qn, |
| 1056 | .kind = (CBMStringRefKind)kind_val, |
| 1057 | }; |
| 1058 | cbm_stringref_push(&ctx->result->string_refs, ctx->arena, ref); |
| 1059 | return; |
| 1060 | } |
| 1061 | if (!is_string_node(kind)) { |
| 1062 | return; |
| 1063 | } |
| 1064 | |
| 1065 | /* Extract string content */ |
| 1066 | char *text = cbm_node_text(ctx->arena, node, ctx->source); |
| 1067 | if (!text || !text[0]) { |
| 1068 | return; |
| 1069 | } |
| 1070 | |
| 1071 | /* Strip quotes if present */ |
| 1072 | int len = (int)strlen(text); |
| 1073 | const char *content = text; |
| 1074 | if (len >= CBM_QUOTE_PAIR && (text[0] == '"' || text[0] == '\'')) { |
| 1075 | content = text + SKIP_ONE; |
| 1076 | len -= PAIR_LEN; |
| 1077 | if (len <= 0) { |
| 1078 | return; |
| 1079 | } |
| 1080 | } |
| 1081 | |
| 1082 | /* Classify */ |
| 1083 | int kind_val = cbm_classify_string(content, len); |
| 1084 | if (kind_val < 0) { |
| 1085 | return; |
| 1086 | } |
| 1087 | |
| 1088 | /* Build null-terminated content string in arena */ |
| 1089 | char *val = cbm_arena_strndup(ctx->arena, content, (size_t)len); |
| 1090 | if (!val) { |
| 1091 | return; |
| 1092 | } |
| 1093 | |
| 1094 | CBMStringRef ref = { |
| 1095 | .value = val, |
no test coverage detected