Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions crates/oxc_angular_compiler/src/linker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,68 @@ fn walk_expression(
Expression::ClassExpression(class_expr) => {
walk_class_body(&class_expr.body, source, filename, options, edits);
}
// Declarations nested in data, as Babel's linker visits every call: Deepkit's runtime types record each
// static property's initializer as a function in a `static __type = [...]` array, so a class compiled
// with them carries a second `ɵɵngDeclareComponent(...)` there. Unlinked, its `ngImport: i0` keeps all of
// @angular/core in the bundle.
Expression::ArrayExpression(array) => {
for element in &array.elements {
match element {
oxc_ast::ast::ArrayExpressionElement::SpreadElement(spread) => {
walk_expression(&spread.argument, source, filename, options, edits);
}
oxc_ast::ast::ArrayExpressionElement::Elision(_) => {}
other => {
if let Some(expr) = other.as_expression() {
walk_expression(expr, source, filename, options, edits);
}
}
}
}
}
Expression::ObjectExpression(object) => {
for property in &object.properties {
match property {
oxc_ast::ast::ObjectPropertyKind::ObjectProperty(prop) => {
walk_expression(&prop.value, source, filename, options, edits);
Comment thread
Brooooooklyn marked this conversation as resolved.
}
oxc_ast::ast::ObjectPropertyKind::SpreadProperty(spread) => {
walk_expression(&spread.argument, source, filename, options, edits);
}
}
}
}
Expression::NewExpression(new_expr) => {
walk_expression(&new_expr.callee, source, filename, options, edits);
for arg in &new_expr.arguments {
if let Argument::SpreadElement(_) = arg {
continue;
Comment thread
Brooooooklyn marked this conversation as resolved.
}
walk_expression(arg.to_expression(), source, filename, options, edits);
}
}
Expression::StaticMemberExpression(member) => {
walk_expression(&member.object, source, filename, options, edits);
Comment thread
Brooooooklyn marked this conversation as resolved.
}
Expression::ComputedMemberExpression(member) => {
walk_expression(&member.object, source, filename, options, edits);
walk_expression(&member.expression, source, filename, options, edits);
}
Expression::UnaryExpression(unary) => {
walk_expression(&unary.argument, source, filename, options, edits);
}
Expression::BinaryExpression(binary) => {
walk_expression(&binary.left, source, filename, options, edits);
walk_expression(&binary.right, source, filename, options, edits);
}
Expression::AwaitExpression(await_expr) => {
walk_expression(&await_expr.argument, source, filename, options, edits);
}
Expression::TemplateLiteral(template) => {
for expr in &template.expressions {
walk_expression(expr, source, filename, options, edits);
}
}
_ => {}
}
}
Expand Down
18 changes: 18 additions & 0 deletions crates/oxc_angular_compiler/tests/linker_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,21 @@ MyDir.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0
result.code
);
}

/// Babel's linker links every declaration call; Deepkit's runtime types keep a copy of each static initializer in a
/// `__type` array, whose declarations must not stay unlinked (their `ngImport: i0` keeps all of @angular/core)
#[test]
fn test_link_declarations_nested_in_arrays_and_objects() {
let allocator = Allocator::default();
let code = r#"import * as i0 from "@angular/core";
class Cmp {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: Cmp, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.__type = ['ɵfac', function () { return i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: Cmp, deps: [], target: i0.ɵɵFactoryTarget.Component }); }]; }
}
const table = { factory: () => i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: Cmp, deps: [], target: i0.ɵɵFactoryTarget.Component }) };
"#;
let result = link(&allocator, code, "test.mjs");
assert!(result.linked);
assert!(!result.code.contains("ɵɵngDeclare"), "every declaration links:\n{}", result.code);
assert!(!result.code.contains("ngImport"), "{}", result.code);
}
Loading