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],