Skip to content

Commit 1c6cf8a

Browse files
petebacondarwinmhevery
authored andcommitted
fix(compiler-cli): do not drop non-Angular decorators when downleveling (#39577)
There is a compiler transform that downlevels Angular class decorators to static properties so that metadata is available for JIT compilation. The transform was supposed to ignore non-Angular decorators but it was actually completely dropping decorators that did not conform to a very specific syntactic shape (i.e. the decorator was a simple identifier, or a namespaced identifier). This commit ensures that all non-Angular decorators are kepts as-is even if they are built using a syntax that the Angular compiler does not understand. Fixes #39574 PR Close #39577
1 parent 7bd0133 commit 1c6cf8a

File tree

2 files changed

+27
-7
lines changed

2 files changed

+27
-7
lines changed

packages/compiler-cli/src/transformers/downlevel_decorators_transform.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -538,12 +538,17 @@ export function getDownlevelDecoratorsTransform(
538538
}
539539
newMembers.push(ts.visitEachChild(member, decoratorDownlevelVisitor, context));
540540
}
541-
const decorators = host.getDecoratorsOfDeclaration(classDecl) || [];
541+
542+
// The `ReflectionHost.getDecoratorsOfDeclaration()` method will not return certain kinds of
543+
// decorators that will never be Angular decorators. So we cannot rely on it to capture all
544+
// the decorators that should be kept. Instead we start off with a set of the raw decorators
545+
// on the class, and only remove the ones that have been identified for downleveling.
546+
const decoratorsToKeep = new Set<ts.Decorator>(classDecl.decorators);
547+
const possibleAngularDecorators = host.getDecoratorsOfDeclaration(classDecl) || [];
542548

543549
let hasAngularDecorator = false;
544550
const decoratorsToLower = [];
545-
const decoratorsToKeep: ts.Decorator[] = [];
546-
for (const decorator of decorators) {
551+
for (const decorator of possibleAngularDecorators) {
547552
// We only deal with concrete nodes in TypeScript sources, so we don't
548553
// need to handle synthetically created decorators.
549554
const decoratorNode = decorator.node! as ts.Decorator;
@@ -557,8 +562,7 @@ export function getDownlevelDecoratorsTransform(
557562

558563
if (isNgDecorator && !skipClassDecorators) {
559564
decoratorsToLower.push(extractMetadataFromSingleDecorator(decoratorNode, diagnostics));
560-
} else {
561-
decoratorsToKeep.push(decoratorNode);
565+
decoratorsToKeep.delete(decoratorNode);
562566
}
563567
}
564568

@@ -581,8 +585,9 @@ export function getDownlevelDecoratorsTransform(
581585
ts.createNodeArray(newMembers, classDecl.members.hasTrailingComma), classDecl.members);
582586

583587
return ts.updateClassDeclaration(
584-
classDecl, decoratorsToKeep.length ? decoratorsToKeep : undefined, classDecl.modifiers,
585-
classDecl.name, classDecl.typeParameters, classDecl.heritageClauses, members);
588+
classDecl, decoratorsToKeep.size ? Array.from(decoratorsToKeep) : undefined,
589+
classDecl.modifiers, classDecl.name, classDecl.typeParameters, classDecl.heritageClauses,
590+
members);
586591
}
587592

588593
/**

packages/compiler-cli/test/transformers/downlevel_decorators_transform_spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,21 @@ describe('downlevel decorator transform', () => {
189189
expect(output).not.toContain('MyClass.decorators');
190190
});
191191

192+
it('should not downlevel non-Angular class decorators generated by a builder', () => {
193+
const {output} = transform(`
194+
@DecoratorBuilder().customClassDecorator
195+
export class MyClass {}
196+
`);
197+
198+
expect(diagnostics.length).toBe(0);
199+
expect(output).toContain(dedent`
200+
MyClass = tslib_1.__decorate([
201+
DecoratorBuilder().customClassDecorator
202+
], MyClass);
203+
`);
204+
expect(output).not.toContain('MyClass.decorators');
205+
});
206+
192207
it('should downlevel Angular-decorated class member', () => {
193208
const {output} = transform(`
194209
import {Input} from '@angular/core';

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy