| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Angular v22 changed the safe-navigation operator (`?.`) in template expressions to yield `undefined` via native optional chaining, gated by the `legacyOptionalChaining` compiler option. OXC unconditionally emitted the legacy `== null ? null` ternary, so v22+ projects got the wrong runtime value for any `?.` expression. Changes: - Add `legacyOptionalChaining` to `TransformOptions` (NAPI + Rust) and thread it through ingest into the compilation jobs. The effective default is derived from `angularVersion`: legacy for < v22, modern (native `?.`) for >= v22, and legacy when the version is unknown (matches Angular's conservative fallback). - Add an `optional` flag to the resolved IR read/call nodes (`ResolvedPropertyRead`/`ResolvedKeyedRead`/`ResolvedCall`) and pass it through reify so it renders as native `?.` / `?.[]` / `?.()`. - Rewrite `expand_safe_reads` to branch per node: legacy builds the `SafeTernary` (`== null ? null`); modern rewrites each safe access into the equivalent optional resolved read (no temporaries needed). - Support the `$safeNavigationMigration(...)` escape hatch: a wrapped subtree is forced back to legacy null semantics even on a modern target, and the wrapper is stripped. Two deviations from the issue text, both to match the reference compiler (angular/angular@2896c93cc1): - The modern form is native optional chaining (`ctx.user?.name`), not the `== null ? undefined` ternary the issue described. Both yield `undefined` at runtime; native `?.` matches Angular's emitted output. - The magic function shipped in v22 is `$safeNavigationMigration(...)`, not `$null(...)` (the commit message named `$null` but the code renamed it). Partial/linker output keeps legacy semantics for now; threading the facade field through partial emit is deferred (issue required-work #4). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Here are some automated review suggestions for this pull request.
Reviewed commit: 1269b230ee
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Sorry, something went wrong.
…d helper
The migration marker was matched by property name alone, so a legitimate
template call such as `svc.$safeNavigationMigration(user)` was stripped and
replaced by its argument instead of invoking `svc`.
Mirror Angular's design: add a dedicated `removeSafeNavigationMigration` phase
that runs before `resolveNames` (right after `deleteAnyCasts`, its upstream
position) and keys on a bare `LexicalRead("$safeNavigationMigration")` — which
only ever represents an unqualified reference, the same discriminator
`deleteAnyCasts` uses for `$any`. The phase wraps the argument in a new
`SafeNavigationMigration` IR node whose subtree is visited with the
`IN_SAFE_NAVIGATION_MIGRATION` flag; `expandSafeReads` honors that flag to force
legacy `== null ? null` semantics and unwraps the marker, replacing the previous
name-only detection that ran post-resolution.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve conflicts from PR #330 merge: - metadata.rs: Keep v22 control-property method - expand_safe_reads.rs: Use flag-based single-pass approach from main - expression.rs: Add SafeNavigationMigrationExpr struct - integration_test.rs: Add qualified call test Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com>
| Back | FazBrowse Home | New Git URL |
Summary
Angular v22 changed the safe-navigation operator (?.) in template expressions to yield undefined via native optional chaining, gated behind the legacyOptionalChaining compiler option (angular/angular@2896c93cc1). OXC unconditionally emitted the legacy == null ? null ternary, so every ?. expression in a v22+ project got the wrong runtime value (null instead of undefined). This is a silent, time-bombed regression for anyone upgrading to v22.
This PR makes OXC version-aware and faithful to the reference compiler's emitted output.
Closes #317.
What changed
Deviations from the issue text (both to match the reference compiler)
Out of scope
Partial/linker output keeps legacy semantics for now; threading the legacyOptionalChaining facade field through partial emit is deferred (issue required-work #4). Wiring a user's tsconfig angularCompilerOptions.legacyOptionalChaining → this NAPI option lives in the JS build-plugin layer.
Verification
Output was diffed against Angular's own compliance goldens (r3_view_compiler/safe_access) by running the exact fixture templates through OXC at v22:
The only difference anywhere is OXC's emitter wrapping ternaries in extra parentheses — pre-existing style, semantically identical.
Test plan
🤖 Generated with Claude Code