Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

`$safeNavigationMigration(...)` in an event listener reads template locals from the wrong context

Fermée
#585 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

Une pull request liée a déjà été fusionnée.

  • #587 par @edbzn — fusionnée

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
55/100
Type d'issue
Bug
Clarté
Plutôt claire
Activité
Active
Stack technique
rust
Domaine
backend, compilers

Piste de recherche

Start by reading remove_safe_navigation_migration and the name resolution phase that handles listener handlerOps; the issue identifies both as possible points where the local scope is lost. Compare listener compilation with the working property binding in a focused reproduction using the supplied template. Done when the listener reads the restored option_r2 value and a regression test covers template locals inside migrated listener expressions.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

Summary

When $safeNavigationMigration(expr) is used inside an event binding, OXC resolves template-local
variables in expr (@for items, @if … as x aliases, let- variables) against the listener's
ctx (ctx.option) instead of the local restored from the view (option_r2). The argument is
always undefined, so the expression evaluates to null.

Property bindings that use the same builtin compile correctly. The bug is specific to listener
handler ops.

Reproduction (@oxc-angular/[email protected], @oxc-angular/vite/api)

import { transformAngularFile } from '@oxc-angular/vite/api';

const src = `import { Component } from '@angular/core';
@Component({ selector: 'x-probe', template: \`
@for (option of options; track $index) {
  <button (click)="pick(option?.value); pick2($safeNavigationMigration(option?.value))"
          [title]="$safeNavigationMigration(option?.label)"></button>
}\` })
export class Probe { options: any[] = []; pick(v: any) {} pick2(v: any) {} }`;

const r = await transformAngularFile(src, '/tmp/probe.component.ts', {}, { templates: {}, styles: {} });
console.log(r.code);
Actual
i0.ɵɵlistener("click", function Probe_For_1_Template_button_click_0_listener() {
  const option_r2 = i0.ɵɵrestoreView(_r1).$implicit;
  const ctx_r2 = i0.ɵɵnextContext();
  ctx_r2.pick(((option_r2 == null) ? null : option_r2.value));          // correct
  return i0.ɵɵresetView(ctx_r2.pick2(((ctx.option == null) ? null : ctx.option.value))); // wrong: ctx.option
});
// update block, correct:
i0.ɵɵproperty("title", ((option_r3 == null) ? null : option_r3.label));
Expected (what ngc emits)

The listener should read option_r2 for both calls:
ctx_r2.pick2(((option_r2 == null) ? null : option_r2.value)).

Impact

Angular's ng update migration for the v22 safe-navigation change inserts $safeNavigationMigration
automatically. Any migrated listener such as (click)="select($safeNavigationMigration(item?.id))"
inside @for/@if as/*ngFor now passes null at runtime. There's no compile error. In our
monorepo this broke a shared select component (every dropdown emitted null) and profile
activation toggles, and failed 21 component tests across 4 projects that pass under
@analogjs/vite-plugin-angular / ngc. Rewriting the three affected bindings as x?.y ?? null
made all 21 pass under OXC.

Possible cause

remove_safe_navigation_migration iterates view.create and view.update. Angular's
unit.ops() also yields each listener's handlerOps. If the marker in handler ops isn't converted
before resolve_names, or is converted with a different scope, the argument's LexicalReads skip
the restored-view locals. Unverified, this is a guess from reading the phase source.

Environment

  • @oxc-angular/vite 0.0.41 (linux-x64-gnu binding)
  • Angular 22.2.0, Vite 7.3.6
Langage dominant
Rust
Étoiles
240
Forks
24
Merge moyen
1 j 14 h
PR mergées (30 j)
77

Préparer son environnement

Ce projet ne fournit ni conteneur de développement, ni Dockerfile, ni guide de contribution : l'installation est à votre charge. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de voidzero-dev/oxc-angular-compiler

Toutes les issues de voidzero-dev/oxc-angular-compiler

Issues similaires

Plus d'issues Rust

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.