Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0961ef6
fix(decorator): hoist consts referenced by emitted Ivy definitions
Brooooooklyn May 27, 2026
8ceae12
test: scope unresolved-interpolation assertion to ɵcmp selectors only
Brooooooklyn May 27, 2026
96f8c9a
fix(hoist): transitive deps + deterministic dedup for shared statements
Brooooooklyn May 27, 2026
2893ba7
fix(hoist): boundary + function-call transitive TDZ deps
Brooooooklyn May 27, 2026
6165886
refactor(hoist): resolve bindings via oxc_semantic SymbolIds
Brooooooklyn May 27, 2026
4d4a3fc
fix(hoist): lazy fn-value, optional chain, destructured bindings
Brooooooklyn May 27, 2026
62de526
fix(hoist): per-class eager-call, IIFE metadata, multi-decl class-ref…
Brooooooklyn May 27, 2026
311a41a
fix(hoist): chase param default refs of eagerly called functions
Brooooooklyn May 27, 2026
437d4da
fix(hoist): chase destructuring defaults; walk IIFE bodies in eagerly…
Brooooooklyn May 27, 2026
3753827
fix(hoist): close class-TDZ guard transitively; walk assignment refs
Brooooooklyn May 27, 2026
9c3c38d
fix(hoist): chase fn-valued binding bodies in guard, cascade, and topo
Brooooooklyn May 27, 2026
0de5f1c
fix(hoist): index class constructors and walk eager class-expr parts
Brooooooklyn May 28, 2026
174c796
fix(hoist): walk classes inside fn bodies, branch callees, tag templa…
Brooooooklyn May 28, 2026
730983c
fix(hoist): record indirect/bind callees on tagged-template tags
Brooooooklyn May 28, 2026
d542220
fix(hoist): chase fn-valued binding bodies for pre-class bindings too
Brooooooklyn May 28, 2026
b493490
chore(hoist): drop stale 'moved from' comment in BFS
Brooooooklyn May 28, 2026
7348273
chore(hoist): strip PR/issue bookkeeping references from comments
Brooooooklyn May 28, 2026
9575f2c
fix(hoist): descend through branch receivers; symmetric topo eager close
Brooooooklyn May 28, 2026
9e50744
fix(hoist): chase named nested function bodies in body visitor
Brooooooklyn May 28, 2026
7df59ff
fix(hoist): chase locally-bound arrow/fn helpers when called eagerly
Brooooooklyn May 28, 2026
342d625
fix(hoist): index nested fn declarations lazily; fold only at call sites
Brooooooklyn May 28, 2026
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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ oxc_napi = "0.133"
oxc_parser = "0.133"
oxc_semantic = "0.133"
oxc_span = "0.133"
oxc_syntax = "0.133"
oxc_sourcemap = "7.0.0"
oxc_str = "0.133"
oxc_transformer = "0.133"
Expand Down
2 changes: 2 additions & 0 deletions crates/oxc_angular_compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ doctest = false
[dependencies]
oxc_allocator = { workspace = true }
oxc_ast = { workspace = true }
oxc_ast_visit = { workspace = true }
oxc_diagnostics = { workspace = true }
oxc_parser = { workspace = true }
oxc_semantic = { workspace = true }
oxc_span = { workspace = true }
oxc_syntax = { workspace = true }
oxc_sourcemap = { workspace = true }
oxc_str = { workspace = true }
oxc_transformer = { workspace = true }
Expand Down
2,561 changes: 2,561 additions & 0 deletions crates/oxc_angular_compiler/src/component/hoist.rs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions crates/oxc_angular_compiler/src/component/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod cross_file_elision;
mod decorator;
mod definition;
mod dependency;
mod hoist;
mod import_elision;
mod metadata;
mod namespace_registry;
Expand Down
28 changes: 28 additions & 0 deletions crates/oxc_angular_compiler/src/component/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use super::decorator::{
extract_component_metadata, find_component_decorator, find_component_decorator_span,
};
use super::definition::{const_value_to_expression, generate_component_definitions};
use super::hoist::{collect_hoist_edits, program_has_angular_decorated_class};
use super::import_elision::{ImportElisionAnalyzer, import_elision_edits};
use super::metadata::{AngularVersion, ComponentMetadata, HostMetadata};
use super::namespace_registry::NamespaceRegistry;
Expand Down Expand Up @@ -2567,6 +2568,33 @@ pub fn transform_angular_file(
}
}

// 5e. TDZ-safe hoisting of top-level bindings referenced by decorator
// metadata but declared after the decorated class. Without this, the
// emitted `ɵcmp` static field's `ɵɵProvidersFeature` would evaluate the
// reference at class-definition time and throw `ReferenceError`. See
// issue #287.
//
// The hoister resolves identifier references through `oxc_semantic` so
// a nested-scope shadow of a top-level name can't be mistaken for the
// top-level binding itself.
//
// Gate the Semantic build behind a cheap top-level scan: a real Angular
// codebase contains plenty of plain `.ts` helpers, type-only modules, and
// services without `@Injectable` that we route through this function. For
// those, building a full symbol table just to discover there's nothing to
// hoist is pure overhead.
if program_has_angular_decorated_class(&parser_ret.program) {
// Semantic builder errors (redeclarations, etc.) are intentionally
// dropped: the parser already captured syntax errors into
// `result.diagnostics` upstream, and Semantic-level diagnostics here
// aren't actionable for the hoist pass — we treat the input as
// best-effort and rely on the host build to surface genuine errors.
// The JIT path (see ~line 1380) follows the same convention.
let hoist_semantic =
oxc_semantic::SemanticBuilder::new().build(&parser_ret.program).semantic;
edits.extend(collect_hoist_edits(&parser_ret.program, source, &hoist_semantic));
}

// Apply all edits in one pass
if options.sourcemap {
let (code, map) = apply_edits_with_sourcemap(source, edits, path);
Expand Down
Loading
Loading