Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 13 additions & 3 deletions napi/angular-compiler/e2e/compare/fixtures/known-differences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ interface KnownDifference {
fields: string[]
/** Every import difference, exactly as `compareImports` reports it. */
importDiffs?: ImportDiff[]
/** Every setClassMetadata difference, as `Class.field`, e.g. `MyComponent.setClassMetadata`. */
metadataDiffs?: string[]
/** Why each difference exists. */
reasons: string[]
}
Expand All @@ -33,6 +35,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 CTOR_PARAM_TYPE =
'ctorParams emits the parameter`s type name where ngtsc emits type: undefined for type-only annotations (Oxc emit bug, issue #563)'
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)'

Expand All @@ -59,7 +63,8 @@ export const KNOWN_DIFFERENCES: Record<string, KnownDifference> = {
actual: ['Inject', 'Injectable', 'InjectionToken'],
},
],
reasons: [SET_CLASS_METADATA_IMPORT],
metadataDiffs: ['TestableService.setClassMetadata.ctorParams'],
reasons: [SET_CLASS_METADATA_IMPORT, CTOR_PARAM_TYPE],
},
'class-metadata/class-metadata-with-inject': {
fields: [],
Expand All @@ -71,7 +76,8 @@ export const KNOWN_DIFFERENCES: Record<string, KnownDifference> = {
actual: ['Component', 'Inject', 'InjectionToken'],
},
],
reasons: [SET_CLASS_METADATA_IMPORT],
metadataDiffs: ['InjectMetaComponent.setClassMetadata.ctorParams'],
reasons: [SET_CLASS_METADATA_IMPORT, CTOR_PARAM_TYPE],
},
'full-file/component-with-services': {
fields: [],
Expand All @@ -83,7 +89,8 @@ export const KNOWN_DIFFERENCES: Record<string, KnownDifference> = {
actual: ['Component', 'Inject', 'InjectionToken', 'inject'],
},
],
reasons: [SET_CLASS_METADATA_IMPORT],
metadataDiffs: ['ComponentWithServices.setClassMetadata.ctorParams'],
reasons: [SET_CLASS_METADATA_IMPORT, CTOR_PARAM_TYPE],
},
'component-meta/change-detection-default': {
fields: ['ChangeDetectionDefaultComponent.ɵcmp'],
Expand Down Expand Up @@ -111,14 +118,17 @@ export const KNOWN_DIFFERENCES: Record<string, KnownDifference> = {
},
'edge-cases/aliased-injectable': {
fields: ['AliasedService.ɵfac'],
metadataDiffs: ['AliasedService.setClassMetadata'],
reasons: [ALIASED_INJECTABLE],
},
'edge-cases/multiple-custom-decorators': {
fields: ['MultiDecoratorComponent.ɵcmp', 'MultiDecoratorComponent.ɵfac'],
metadataDiffs: ['MultiDecoratorComponent.setClassMetadata'],
reasons: [CUSTOM_DECORATOR],
},
'edge-cases/single-custom-decorator': {
fields: ['MyComponent.ɵcmp', 'MyComponent.ɵfac'],
metadataDiffs: ['MyComponent.setClassMetadata'],
reasons: [CUSTOM_DECORATOR],
},
'full-file/component-with-pipes': {
Expand Down
34 changes: 33 additions & 1 deletion napi/angular-compiler/e2e/compare/fixtures/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,34 @@ async function testFixture(fixture: Fixture, verbose?: boolean): Promise<Fixture
`import ${diff.moduleSource} expected { ${(diff.expected ?? []).join(', ')} } ` +
`got { ${(diff.actual ?? []).join(', ')} }`,
)
const allUndocumented = [...undocumented, ...undocumentedImports]
const undocumentedMetadata = (result.classMetadataDiffs ?? [])
.map((diff) => `${diff.className}.${diff.field}`)
.filter((field) => !(known.metadataDiffs ?? []).includes(field))
Comment thread
Brooooooklyn marked this conversation as resolved.
const observedMetadata = new Set(
(result.classMetadataDiffs ?? []).map((diff) => `${diff.className}.${diff.field}`),
)
const unobservedMetadata = (known.metadataDiffs ?? []).filter(
(field) => !observedMetadata.has(field),
)
const allUndocumented = [...undocumented, ...undocumentedImports, ...undocumentedMetadata]
if (allUndocumented.length > 0) {
return {
...result,
knownDifferences,
undocumentedFields: [...new Set(allUndocumented)],
}
}
// A declared metadata diff that was not observed means the bug was fixed
// (or moved) — surface it like a stale entry so the exemption cannot
// silently re-allow a regression.
if (unobservedMetadata.length > 0) {
return {
...result,
status: 'mismatch',
knownDifferences,
staleMetadataFields: unobservedMetadata,
}
}
return { ...result, status: 'known-difference', knownDifferences }
}
if (result.status === 'match') {
Expand Down Expand Up @@ -994,6 +1014,18 @@ export function printFixtureSummary(report: FixtureReport): void {
console.log(` ${result.fixture.category}/${result.fixture.name}`)
}
}
const staleMetadataFixtures = report.fixtures.filter((r) => r.staleMetadataFields)
if (staleMetadataFixtures.length > 0) {
console.log(
'\nStale Metadata Allowlist Entries (declared in known-differences.ts but no longer observed):',
)
console.log('-'.repeat(50))
for (const result of staleMetadataFixtures) {
console.log(
` ${result.fixture.category}/${result.fixture.name}: ${result.staleMetadataFields!.join(', ')}`,
)
}
}

// Count feature discrepancies
const fixturesWithAsymmetricFeatures = report.fixtures.filter(
Expand Down
3 changes: 3 additions & 0 deletions napi/angular-compiler/e2e/compare/fixtures/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ export interface FixtureResult {
/** Fields that differ in a fixture listed in known-differences.ts but are not documented there */
undocumentedFields?: string[]

/** `metadataDiffs` entries declared in known-differences.ts that no longer occur */
staleMetadataFields?: string[]

/** Oxc compiler output */
oxcOutput?: FixtureCompilerOutput

Expand Down
Loading
Loading