Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1c6cf8a

Browse filesBrowse 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
Copy full SHA for 1c6cf8a

File tree

Expand file treeCollapse file tree

2 files changed

+27
-7
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+27
-7
lines changed
Open diff view settings
Collapse file

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

Copy file name to clipboardExpand all lines: packages/compiler-cli/src/transformers/downlevel_decorators_transform.ts
+12-7Lines 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
/**
Collapse file

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

Copy file name to clipboardExpand all lines: packages/compiler-cli/test/transformers/downlevel_decorators_transform_spec.ts
+15Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.