Skip to content

Commit bd79af5

Browse files
Merge branch 'main' into fix/quarantine-exit-nonzero
2 parents 05e0cca + e678722 commit bd79af5

59 files changed

Lines changed: 599344 additions & 125 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎THIRD_PARTY.md‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ The core runtime headers in `internal/cbm/vendored/common/tree_sitter/`
3737

3838
## Tree-sitter Grammars
3939

40-
159 pre-generated parsers are vendored in `internal/cbm/vendored/grammars/<lang>/`
40+
160 pre-generated parsers are vendored in `internal/cbm/vendored/grammars/<lang>/`
4141
(generated `parser.c` plus `scanner.c` where applicable, compiled statically).
4242
Each grammar is the work of its upstream authors and each grammar directory
4343
contains the upstream `LICENSE` file.
@@ -54,10 +54,15 @@ License summary:
5454
`pine` is **ISC** (declared by its upstream).
5555
- The grammars authored in-house for this project (`cobol`, `form`, `janet`,
5656
`magma`, `protobuf`, `wolfram`) are **MIT** under the project's own license,
57-
(c) DeusData. Six further grammars (`assembly`, `cfml`, `cfscript`,
58-
`dotenv`, `pine`, `qml`) are self-maintained forks that retain their
59-
original upstream authors' licenses — see the manifest for per-grammar
60-
provenance.
57+
(c) DeusData. Seven further grammars (`arkts`, `assembly`, `cfml`,
58+
`cfscript`, `dotenv`, `pine`, `qml`) are self-maintained forks that retain
59+
their original upstream authors' licenses — see the manifest for per-grammar
60+
provenance. `arkts` is a first-party derivative of
61+
[tree-sitter/tree-sitter-typescript](https://github.com/tree-sitter/tree-sitter-typescript)
62+
(MIT, (c) 2017 Max Brunsfeld; on the
63+
[tree-sitter-javascript](https://github.com/tree-sitter/tree-sitter-javascript)
64+
base, MIT, (c) 2014 Max Brunsfeld) with (c) 2026 DeusData ArkTS additions;
65+
its grammar source lives in `tools/tree-sitter-arkts/`.
6166

6267
### tree-sitter-objectscript (UDL + routine)
6368

‎internal/cbm/cbm.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ typedef enum {
174174
CBM_LANG_OBJECTSCRIPT_UDL, // InterSystems ObjectScript UDL (.cls class files)
175175
CBM_LANG_OBJECTSCRIPT_ROUTINE, // InterSystems ObjectScript routine (.mac/.int/.rtn/.inc)
176176
CBM_LANG_OBJECTSCRIPT_EXPORT, // InterSystems Studio Export XML (<Export generator="Cache">)
177+
CBM_LANG_ARKTS, // ArkTS (HarmonyOS/OpenHarmony .ets — TypeScript superset + ArkUI)
177178
CBM_LANG_COUNT
178179
} CBMLanguage;
179180

@@ -551,6 +552,7 @@ typedef struct {
551552
typedef struct {
552553
const char *names[CBM_MAX_STRING_CONSTANTS];
553554
const char *values[CBM_MAX_STRING_CONSTANTS];
555+
bool is_url_builder[CBM_MAX_STRING_CONSTANTS];
554556
int count;
555557
} CBMStringConstantMap;
556558

@@ -726,6 +728,9 @@ void cbm_channels_push(CBMChannelArray *arr, CBMArena *a, CBMChannel ch);
726728
// --- Sub-extractor entry points ---
727729

728730
void cbm_extract_definitions(CBMExtractCtx *ctx);
731+
/* Internal companion for embedded-language trees that contribute definitions
732+
* to an existing host-file Module rather than minting a second Module. */
733+
void cbm_extract_definitions_without_module(CBMExtractCtx *ctx);
729734
// dbt lineage for Jinja-templated SQL models: emits a Model def plus one usage
730735
// per ref()/source() call. No-op unless the file parses as SQL and actually
731736
// contains a dbt builtin call. Defined in extract_dbt.c.

‎internal/cbm/extract_calls.c‎

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,29 @@ enum { MIN_PRINTABLE = 0x20 };
3030
/* Handler arg scan start index (skip first positional). */
3131
enum { HANDLER_START_IDX = 1 };
3232

33-
/* Look up a module-level string constant by name. */
33+
/* Look up a module-level string constant by name. URL-builder entries share the
34+
* map but are not constants: a bare `thingPath` reference is the function, not
35+
* the URL it would build (issue #1009). */
3436
static const char *lookup_string_constant(const CBMExtractCtx *ctx, const char *name) {
3537
if (!name || !name[0]) {
3638
return NULL;
3739
}
3840
const CBMStringConstantMap *map = &ctx->string_constants;
3941
for (int i = 0; i < map->count; i++) {
40-
if (strcmp(map->names[i], name) == 0) {
42+
if (!map->is_url_builder[i] && strcmp(map->names[i], name) == 0) {
43+
return map->values[i];
44+
}
45+
}
46+
return NULL;
47+
}
48+
49+
static const char *lookup_url_builder(const CBMExtractCtx *ctx, const char *name) {
50+
if (!name || !name[0]) {
51+
return NULL;
52+
}
53+
const CBMStringConstantMap *map = &ctx->string_constants;
54+
for (int i = 0; i < map->count; i++) {
55+
if (map->is_url_builder[i] && strcmp(map->names[i], name) == 0) {
4156
return map->values[i];
4257
}
4358
}
@@ -1855,8 +1870,22 @@ static void extract_call_args(CBMExtractCtx *ctx, TSNode args, CBMCall *call) {
18551870
ca->index = positional_idx++;
18561871
if (is_string_like(ak) && ca->expr) {
18571872
ca->value = strip_quotes(ctx->arena, ca->expr);
1873+
} else if (strcmp(ak, "template_string") == 0) {
1874+
/* Flattened {} form so downstream url-arg detection joins the
1875+
* canonical server route shape (issue #1006/#1009). */
1876+
ca->value = cbm_template_string_text(ctx->arena, arg_node, ctx->source);
18581877
} else if (strcmp(ak, "identifier") == 0 && ca->expr) {
18591878
ca->value = lookup_string_constant(ctx, ca->expr);
1879+
} else if (strcmp(ak, "call_expression") == 0) {
1880+
/* URL-builder helper call (issue #1009): resolve
1881+
* client(buildPath(id)) through the per-file builder map. */
1882+
TSNode fn = ts_node_child_by_field_name(arg_node, TS_FIELD("function"));
1883+
if (!ts_node_is_null(fn) && strcmp(ts_node_type(fn), "identifier") == 0) {
1884+
char *fname = cbm_node_text(ctx->arena, fn, ctx->source);
1885+
if (fname) {
1886+
ca->value = lookup_url_builder(ctx, fname);
1887+
}
1888+
}
18601889
}
18611890
call->arg_count++;
18621891
}
@@ -2085,6 +2114,19 @@ static const char *extract_url_or_topic_arg(CBMExtractCtx *ctx, TSNode args) {
20852114
}
20862115
}
20872116

2117+
/* URL-builder helper call (issue #1009): `client(buildPath(id))` — the
2118+
* builder's returned URL was recorded in the per-file constant map. */
2119+
if (strcmp(ak, "call_expression") == 0) {
2120+
TSNode fn = ts_node_child_by_field_name(arg, TS_FIELD("function"));
2121+
if (!ts_node_is_null(fn) && strcmp(ts_node_type(fn), "identifier") == 0) {
2122+
char *fname = cbm_node_text(ctx->arena, fn, ctx->source);
2123+
const char *val = fname ? lookup_url_builder(ctx, fname) : NULL;
2124+
if (val) {
2125+
return val;
2126+
}
2127+
}
2128+
}
2129+
20882130
if (ai < MAX_POSITIONAL_SCAN) {
20892131
const char *val = extract_positional_url(ctx, arg, ak);
20902132
if (val) {
@@ -3296,7 +3338,7 @@ CBMInvocationDescriptor handle_calls(CBMExtractCtx *ctx, TSNode node, const CBML
32963338
// right. Bare calls (helper()) and new_expression have no member
32973339
// receiver, so they keep is_method=false (struct is zero-init).
32983340
if ((ctx->language == CBM_LANG_JAVASCRIPT || ctx->language == CBM_LANG_TYPESCRIPT ||
3299-
ctx->language == CBM_LANG_TSX) &&
3341+
ctx->language == CBM_LANG_TSX || ctx->language == CBM_LANG_ARKTS) &&
33003342
strcmp(ts_node_type(node), "call_expression") == 0) {
33013343
TSNode fn = ts_node_child_by_field_name(node, TS_FIELD("function"));
33023344
if (!ts_node_is_null(fn) && strcmp(ts_node_type(fn), "member_expression") == 0) {

‎internal/cbm/extract_channels.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,7 @@ void cbm_extract_channels(CBMExtractCtx *ctx) {
10581058
case CBM_LANG_JAVASCRIPT:
10591059
case CBM_LANG_TYPESCRIPT:
10601060
case CBM_LANG_TSX:
1061+
case CBM_LANG_ARKTS:
10611062
extract_channels_js(ctx);
10621063
break;
10631064
case CBM_LANG_PYTHON:

‎internal/cbm/extract_defs.c‎

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2550,7 +2550,7 @@ static const char **extract_base_classes(CBMArena *a, TSNode node, const char *s
25502550
}
25512551
// Languages whose heritage is not exposed via a tree-sitter field need
25522552
// dedicated walkers; the generic field/keyword path mis-captures them.
2553-
if (lang == CBM_LANG_TYPESCRIPT || lang == CBM_LANG_TSX) {
2553+
if (lang == CBM_LANG_TYPESCRIPT || lang == CBM_LANG_TSX || lang == CBM_LANG_ARKTS) {
25542554
const char **ts_result = extract_ts_bases(a, node, source);
25552555
if (ts_result) {
25562556
return ts_result;
@@ -3097,7 +3097,7 @@ static char *resolve_param_type_text(CBMArena *a, TSNode param, const char *sour
30973097
return ts_node_is_null(typename) ? NULL : cbm_node_text(a, typename, source);
30983098
}
30993099

3100-
if (lang == CBM_LANG_TYPESCRIPT || lang == CBM_LANG_TSX) {
3100+
if (lang == CBM_LANG_TYPESCRIPT || lang == CBM_LANG_TSX || lang == CBM_LANG_ARKTS) {
31013101
if (strcmp(pk, "required_parameter") == 0 || strcmp(pk, "optional_parameter") == 0) {
31023102
return extract_ts_param_type(a, param, source);
31033103
}
@@ -3230,7 +3230,7 @@ static bool is_signature_implicit_receiver(CBMArena *a, TSNode param, const char
32303230
return true;
32313231
}
32323232

3233-
if (lang == CBM_LANG_TYPESCRIPT || lang == CBM_LANG_TSX) {
3233+
if (lang == CBM_LANG_TYPESCRIPT || lang == CBM_LANG_TSX || lang == CBM_LANG_ARKTS) {
32343234
char *name = signature_receiver_name(a, param, source, false);
32353235
return name && strcmp(name, "this") == 0;
32363236
}
@@ -3658,7 +3658,7 @@ static void extract_func_def(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec
36583658
if (ctx->enclosing_class_qn &&
36593659
(ctx->language == CBM_LANG_CPP || ctx->language == CBM_LANG_CUDA ||
36603660
ctx->language == CBM_LANG_TYPESCRIPT || ctx->language == CBM_LANG_TSX ||
3661-
ctx->language == CBM_LANG_NIX)) {
3661+
ctx->language == CBM_LANG_ARKTS || ctx->language == CBM_LANG_NIX)) {
36623662
def.qualified_name = cbm_arena_sprintf(a, "%s.%s", ctx->enclosing_class_qn, qn_name);
36633663
}
36643664
def.label = "Function";
@@ -3792,7 +3792,7 @@ static void extract_func_def(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec
37923792

37933793
// JS/TS export detection
37943794
if (ctx->language == CBM_LANG_JAVASCRIPT || ctx->language == CBM_LANG_TYPESCRIPT ||
3795-
ctx->language == CBM_LANG_TSX) {
3795+
ctx->language == CBM_LANG_TSX || ctx->language == CBM_LANG_ARKTS) {
37963796
if (is_js_exported(node)) {
37973797
def.is_entry_point = true;
37983798
}
@@ -4395,16 +4395,17 @@ static void extract_class_def(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec
43954395
label = "Interface";
43964396
}
43974397
}
4398-
// Rust/Swift/D: a struct is a distinct kind from a class — emit the precise
4399-
// "Struct" label rather than collapsing it to "Class". Scoped to these three
4400-
// grammar/LSP languages. Rust's struct node is `struct_item`; D's is
4401-
// `struct_declaration`. C/C++/Obj-C keep `struct_specifier` → "Class"
4402-
// (a C++ struct is class-like). "Struct" is a type-like container: every
4403-
// type-resolution / registry / IMPLEMENTS / LSP-registrar consumer routes
4404-
// through cbm_label_is_type_like(), so a struct still resolves as a type for
4405-
// its methods, fields, inheritance and impls.
4398+
// Rust/Swift/D/ArkTS: a struct is a distinct kind from a class — emit the
4399+
// precise "Struct" label rather than collapsing it to "Class". Scoped to
4400+
// these grammar/LSP languages. Rust's struct node is `struct_item`; D's and
4401+
// ArkTS's is `struct_declaration` (an ArkUI @Component custom component).
4402+
// C/C++/Obj-C keep `struct_specifier` → "Class" (a C++ struct is
4403+
// class-like). "Struct" is a type-like container: every type-resolution /
4404+
// registry / IMPLEMENTS / LSP-registrar consumer routes through
4405+
// cbm_label_is_type_like(), so a struct still resolves as a type for its
4406+
// methods, fields, inheritance and impls.
44064407
if (ctx->language == CBM_LANG_RUST || ctx->language == CBM_LANG_SWIFT ||
4407-
ctx->language == CBM_LANG_DLANG) {
4408+
ctx->language == CBM_LANG_DLANG || ctx->language == CBM_LANG_ARKTS) {
44084409
if (strcmp(kind, "struct_item") == 0 || strcmp(kind, "struct_declaration") == 0) {
44094410
label = "Struct";
44104411
}
@@ -5492,6 +5493,7 @@ static void extract_vars_mainstream(CBMExtractCtx *ctx, TSNode node, CBMArena *a
54925493
case CBM_LANG_JAVASCRIPT:
54935494
case CBM_LANG_TYPESCRIPT:
54945495
case CBM_LANG_TSX:
5496+
case CBM_LANG_ARKTS:
54955497
extract_js_vars(ctx, node, a);
54965498
break;
54975499
case CBM_LANG_JAVA: {
@@ -5988,6 +5990,7 @@ static void extract_var_names(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec
59885990
case CBM_LANG_JAVASCRIPT:
59895991
case CBM_LANG_TYPESCRIPT:
59905992
case CBM_LANG_TSX:
5993+
case CBM_LANG_ARKTS:
59915994
case CBM_LANG_JAVA:
59925995
case CBM_LANG_CSHARP:
59935996
case CBM_LANG_CPP:
@@ -6683,6 +6686,10 @@ static void extract_class_fields(CBMExtractCtx *ctx, TSNode class_node, const ch
66836686
def.start_line = ts_node_start_point(child).row + TS_LINE_OFFSET;
66846687
def.end_line = ts_node_end_point(child).row + TS_LINE_OFFSET;
66856688
def.is_exported = cbm_is_exported(name, ctx->language);
6689+
/* Field decorators/annotations (ArkTS @State/@Prop/@Link state members,
6690+
* TS @Input()-style fields, JVM field annotations via the modifiers
6691+
* child) — same extraction the class and method paths already run. */
6692+
def.decorators = extract_decorators(a, child, ctx->source, ctx->language, spec);
66866693

66876694
cbm_defs_push(&ctx->result->defs, a, def);
66886695
}
@@ -7481,7 +7488,8 @@ static void walk_defs(CBMExtractCtx *ctx, TSNode root, const CBMLangSpec *spec,
74817488
bool descend_into_func =
74827489
(ctx->language == CBM_LANG_WOLFRAM || ctx->language == CBM_LANG_TYPESCRIPT ||
74837490
ctx->language == CBM_LANG_JAVASCRIPT || ctx->language == CBM_LANG_TSX ||
7484-
ctx->language == CBM_LANG_ADA || ctx->language == CBM_LANG_NIX);
7491+
ctx->language == CBM_LANG_ARKTS || ctx->language == CBM_LANG_ADA ||
7492+
ctx->language == CBM_LANG_NIX);
74857493
if (!descend_into_func) {
74867494
continue;
74877495
}
@@ -7501,7 +7509,8 @@ static void walk_defs(CBMExtractCtx *ctx, TSNode root, const CBMLangSpec *spec,
75017509
* the class/func paths on the namespace node itself. */
75027510
if (is_namespace_scope_kind(ctx->language, kind, node)) {
75037511
const char *new_enclosing = compute_class_qn(ctx, node, frame.enclosing_class_qn);
7504-
if (ctx->language == CBM_LANG_TYPESCRIPT || ctx->language == CBM_LANG_TSX) {
7512+
if (ctx->language == CBM_LANG_TYPESCRIPT || ctx->language == CBM_LANG_TSX ||
7513+
ctx->language == CBM_LANG_ARKTS) {
75057514
extract_typescript_namespace_def(ctx, node, frame.enclosing_class_qn);
75067515
}
75077516
wd_push_children_reverse(&s, node, new_enclosing);
@@ -7524,6 +7533,19 @@ static void walk_defs(CBMExtractCtx *ctx, TSNode root, const CBMLangSpec *spec,
75247533
free(s.data);
75257534
}
75267535

7536+
void cbm_extract_definitions_without_module(CBMExtractCtx *ctx) {
7537+
const CBMLangSpec *spec = cbm_lang_spec(ctx->language);
7538+
if (!spec) {
7539+
return;
7540+
}
7541+
7542+
// Walk AST for function/class definitions
7543+
walk_defs(ctx, ctx->root, spec, 0);
7544+
7545+
// Extract module-level variables
7546+
extract_variables(ctx, ctx->root, spec);
7547+
}
7548+
75277549
void cbm_extract_definitions(CBMExtractCtx *ctx) {
75287550
const CBMLangSpec *spec = cbm_lang_spec(ctx->language);
75297551
if (!spec) {
@@ -7545,9 +7567,5 @@ void cbm_extract_definitions(CBMExtractCtx *ctx) {
75457567
mod.is_test = ctx->result->is_test_file;
75467568
cbm_defs_push(&ctx->result->defs, a, mod);
75477569

7548-
// Walk AST for function/class definitions
7549-
walk_defs(ctx, ctx->root, spec, 0);
7550-
7551-
// Extract module-level variables
7552-
extract_variables(ctx, ctx->root, spec);
7570+
cbm_extract_definitions_without_module(ctx);
75537571
}

0 commit comments

Comments
 (0)