From f55828e4fb95873de8eaba170581a7ea6e39ed98 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Thu, 8 Oct 2026 12:04:09 +0800 Subject: [PATCH] test(e2e): record the aliased-@Injectable emit difference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `import { Injectable as X }` + `@X(...)` compiles to a working `ɵfac` and setClassMetadata under Oxc; ngtsc's `needsFactory` check compares the written decorator name, so it emits only `ɵprov` pointing at a factory it never generated — an upstream bug (issue #507). Oxc keeps its output; this adds a fixture covering the case and documents the difference in known-differences.ts. --- .../edge-cases/aliased-decorators.fixture.ts | 29 +++++++++++++++++++ .../e2e/compare/fixtures/known-differences.ts | 6 ++++ 2 files changed, 35 insertions(+) create mode 100644 napi/angular-compiler/e2e/compare/fixtures/edge-cases/aliased-decorators.fixture.ts diff --git a/napi/angular-compiler/e2e/compare/fixtures/edge-cases/aliased-decorators.fixture.ts b/napi/angular-compiler/e2e/compare/fixtures/edge-cases/aliased-decorators.fixture.ts new file mode 100644 index 000000000..06d5b52af --- /dev/null +++ b/napi/angular-compiler/e2e/compare/fixtures/edge-cases/aliased-decorators.fixture.ts @@ -0,0 +1,29 @@ +/** + * Fixtures for Angular decorators imported under an alias. + * + * `import { Injectable as X }` + `@X(...)` is an Angular decorator to Oxc, + * which resolves the import binding. ngtsc finds the decorator too, but its + * `needsFactory` check (`injectable.ts`) compares the WRITTEN name + * (`current.name === 'Injectable'`), so an aliased import compiles to a + * broken `ɵprov` referencing a `ɵfac` it never emitted — an upstream bug. + * See https://github.com/voidzero-dev/oxc-angular-compiler/issues/507. + */ +import type { Fixture } from '../types.js' + +export const fixtures: Fixture[] = [ + { + type: 'full-transform', + name: 'aliased-injectable', + category: 'edge-cases', + description: + '@Injectable imported under an alias — Oxc emits a working ɵfac and setClassMetadata; ngtsc emits only ɵprov pointing at a factory it never generated (upstream bug)', + className: 'AliasedService', + sourceCode: ` +import { Injectable as X } from '@angular/core'; + +@X({ providedIn: 'root' }) +export class AliasedService {} + `.trim(), + expectedFeatures: ['ɵɵdefineInjectable'], + }, +] diff --git a/napi/angular-compiler/e2e/compare/fixtures/known-differences.ts b/napi/angular-compiler/e2e/compare/fixtures/known-differences.ts index 867e65194..9629509ce 100644 --- a/napi/angular-compiler/e2e/compare/fixtures/known-differences.ts +++ b/napi/angular-compiler/e2e/compare/fixtures/known-differences.ts @@ -33,6 +33,8 @@ const INJECTABLE_FACTORY_WRAPPER = 'an @Injectable useFactory is wrapped in a function expression where Angular emits an arrow function' const SET_CLASS_METADATA_IMPORT = 'Oxc keeps the @Inject import because its setClassMetadata references it; ngtsc emits the same reference but TypeScript elision still drops the import (upstream emit bug)' +const ALIASED_INJECTABLE = + 'an aliased @Injectable compiles to a broken ɵprov under ngtsc — its needsFactory check compares the written decorator name, so the factory (and setClassMetadata) are never emitted; Oxc emits a working ɵfac (issue #507, kept deliberately)' export const KNOWN_DIFFERENCES: Record = { 'animations/animation-metadata-with-change-detection': { @@ -107,6 +109,10 @@ export const KNOWN_DIFFERENCES: Record = { fields: ['DeferHydrateViewportComponent.ɵcmp'], reasons: [INCREMENTAL_HYDRATION], }, + 'edge-cases/aliased-injectable': { + fields: ['AliasedService.ɵfac'], + reasons: [ALIASED_INJECTABLE], + }, 'edge-cases/multiple-custom-decorators': { fields: ['MultiDecoratorComponent.ɵcmp', 'MultiDecoratorComponent.ɵfac'], reasons: [CUSTOM_DECORATOR],