| 6287 | } |
| 6288 | |
| 6289 | static void extract_class_fields(CBMExtractCtx *ctx, TSNode class_node, const char *class_qn, |
| 6290 | const CBMLangSpec *spec) { |
| 6291 | if (!spec->field_node_types || !spec->field_node_types[0]) { |
| 6292 | return; |
| 6293 | } |
| 6294 | |
| 6295 | TSNode body = find_class_member_body(class_node, ctx->language); |
| 6296 | if (ts_node_is_null(body)) { |
| 6297 | return; |
| 6298 | } |
| 6299 | |
| 6300 | CBMArena *a = ctx->arena; |
| 6301 | uint32_t count = ts_node_named_child_count(body); |
| 6302 | for (uint32_t i = 0; i < count; i++) { |
| 6303 | TSNode child = ts_node_named_child(body, i); |
| 6304 | |
| 6305 | // ObjectScript UDL wraps each member in a class_statement node. |
| 6306 | if (ctx->language == CBM_LANG_OBJECTSCRIPT_UDL && |
| 6307 | strcmp(ts_node_type(child), "class_statement") == 0 && |
| 6308 | ts_node_named_child_count(child) > 0) { |
| 6309 | child = ts_node_named_child(child, 0); |
| 6310 | } |
| 6311 | |
| 6312 | if (!cbm_kind_in_set(child, spec->field_node_types)) { |
| 6313 | continue; |
| 6314 | } |
| 6315 | |
| 6316 | if (is_func_ptr_field(child)) { |
| 6317 | continue; |
| 6318 | } |
| 6319 | |
| 6320 | /* Schema/grammar languages (GraphQL/Prisma/Smali) carry the field name on |
| 6321 | * a plain child rather than a C-style declarator/type field; handle them |
| 6322 | * up front so the generic "type"-field path below doesn't skip them. */ |
| 6323 | if (extract_schema_field(ctx, child, class_qn)) { |
| 6324 | continue; |
| 6325 | } |
| 6326 | |
| 6327 | // ObjectScript UDL member extraction. property/parameter -> Variable; |
| 6328 | // index/trigger/xdata/storage/foreignkey -> labelled members with |
| 6329 | // storage-XML and trigger-body sidecars. |
| 6330 | if (ctx->language == CBM_LANG_OBJECTSCRIPT_UDL) { |
| 6331 | if (strcmp(ts_node_type(child), "property") == 0 || |
| 6332 | strcmp(ts_node_type(child), "parameter") == 0) { |
| 6333 | TSNode pname = cbm_find_child_by_kind(child, "property_name"); |
| 6334 | if (ts_node_is_null(pname)) { |
| 6335 | pname = cbm_find_child_by_kind(child, "parameter_name"); |
| 6336 | } |
| 6337 | if (!ts_node_is_null(pname) && ts_node_named_child_count(pname) > 0) { |
| 6338 | TSNode ident = ts_node_named_child(pname, 0); |
| 6339 | char *pn = cbm_node_text(a, ident, ctx->source); |
| 6340 | if (pn && pn[0]) { |
| 6341 | CBMDefinition pdef; |
| 6342 | memset(&pdef, 0, sizeof(pdef)); |
| 6343 | pdef.name = pn; |
| 6344 | pdef.qualified_name = cbm_arena_sprintf(a, "%s.%s", class_qn, pn); |
| 6345 | pdef.label = "Variable"; |
| 6346 | pdef.file_path = ctx->rel_path; |
no test coverage detected