Skip to content

Commit 65d09f9

Browse files
Brooooooklynclaude
andauthored
fix: linker converts queries/viewQueries to contentQueries/viewQuery for directives (#81)
The linker's link_directive() was missing calls to build_queries(), causing directives with @ContentChild/@ContentChildren/@ViewChild/@ViewChildren to silently lose those queries during linking. This mirrors what link_component() already does correctly. - Close #70 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b67c924 commit 65d09f9

File tree

1 file changed

+83
-0
lines changed
  • crates/oxc_angular_compiler/src/linker

1 file changed

+83
-0
lines changed

crates/oxc_angular_compiler/src/linker/mod.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,21 @@ fn link_directive(
992992
if let Some(selector) = get_string_property(meta, "selector") {
993993
parts.push(format!("selectors: {}", parse_selector(selector)));
994994
}
995+
996+
// Content queries — convert queries array to contentQueries function
997+
if let Some(queries_arr) = get_array_property(meta, "queries") {
998+
if let Some(cq_fn) = build_queries(queries_arr, source, ns, type_name, true) {
999+
parts.push(format!("contentQueries: {cq_fn}"));
1000+
}
1001+
}
1002+
1003+
// View queries — convert viewQueries array to viewQuery function
1004+
if let Some(view_queries_arr) = get_array_property(meta, "viewQueries") {
1005+
if let Some(vq_fn) = build_queries(view_queries_arr, source, ns, type_name, false) {
1006+
parts.push(format!("viewQuery: {vq_fn}"));
1007+
}
1008+
}
1009+
9951010
if let Some(inputs_obj) = get_object_property(meta, "inputs") {
9961011
let converted = convert_inputs_to_definition_format(inputs_obj, source);
9971012
parts.push(format!("inputs: {converted}"));
@@ -2278,6 +2293,74 @@ BrnMenu.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0
22782293
);
22792294
}
22802295

2296+
/// Issue #70: Directive with contentQueries (queries) should produce contentQueries function
2297+
#[test]
2298+
fn test_link_directive_with_content_queries() {
2299+
let allocator = Allocator::default();
2300+
let code = r#"
2301+
import * as i0 from "@angular/core";
2302+
class MyDirective {
2303+
}
2304+
MyDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.0", ngImport: i0, type: MyDirective, selector: "[myDir]", isStandalone: true, queries: [{ propertyName: "items", predicate: SomeComponent, descendants: true }] });
2305+
"#;
2306+
let result = link(&allocator, code, "test.mjs");
2307+
assert!(result.linked);
2308+
assert!(
2309+
result.code.contains("contentQueries:"),
2310+
"Should have contentQueries for directive with queries, got:\n{}",
2311+
result.code
2312+
);
2313+
assert!(
2314+
result.code.contains("contentQuery"),
2315+
"Should call ɵɵcontentQuery, got:\n{}",
2316+
result.code
2317+
);
2318+
}
2319+
2320+
/// Issue #70: Directive with viewQueries should produce viewQuery function
2321+
#[test]
2322+
fn test_link_directive_with_view_queries() {
2323+
let allocator = Allocator::default();
2324+
let code = r#"
2325+
import * as i0 from "@angular/core";
2326+
class MyDirective {
2327+
}
2328+
MyDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.0", ngImport: i0, type: MyDirective, selector: "[myDir]", isStandalone: true, viewQueries: [{ propertyName: "myRef", predicate: ["myRef"], first: true }] });
2329+
"#;
2330+
let result = link(&allocator, code, "test.mjs");
2331+
assert!(result.linked);
2332+
assert!(
2333+
result.code.contains("viewQuery:"),
2334+
"Should have viewQuery for directive with viewQueries, got:\n{}",
2335+
result.code
2336+
);
2337+
assert!(
2338+
result.code.contains("\u{0275}\u{0275}viewQuery"),
2339+
"Should call ɵɵviewQuery, got:\n{}",
2340+
result.code
2341+
);
2342+
}
2343+
2344+
/// Issue #70: Directive with both queries and viewQueries
2345+
#[test]
2346+
fn test_link_directive_with_both_queries() {
2347+
let allocator = Allocator::default();
2348+
let code = r#"
2349+
import * as i0 from "@angular/core";
2350+
class MyDirective {
2351+
}
2352+
MyDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.0", ngImport: i0, type: MyDirective, selector: "[myDir]", isStandalone: true, queries: [{ propertyName: "items", predicate: SomeComponent, descendants: true }], viewQueries: [{ propertyName: "myRef", predicate: ["myRef"], first: true }] });
2353+
"#;
2354+
let result = link(&allocator, code, "test.mjs");
2355+
assert!(result.linked);
2356+
assert!(
2357+
result.code.contains("contentQueries:"),
2358+
"Should have contentQueries, got:\n{}",
2359+
result.code
2360+
);
2361+
assert!(result.code.contains("viewQuery:"), "Should have viewQuery, got:\n{}", result.code);
2362+
}
2363+
22812364
/// Issue #71: Feature ordering — HostDirectivesFeature must come after ProvidersFeature
22822365
/// and before InheritDefinitionFeature
22832366
#[test]

0 commit comments

Comments
 (0)