Skip to content

Commit 8ceac0b

Browse files
committed
refactor(compiler-cli): track member metadata using output AST (angular#63957)
Reworks the logic that tracks the decorator metadata for members to do so using the output AST, rather than wrapping the TypeScript AST. This makes it easier to programmatically generate new members that weren't part of the TypeScript AST before. PR Close angular#63957
1 parent 9af3cf7 commit 8ceac0b

1 file changed

Lines changed: 31 additions & 19 deletions

File tree

  • packages/compiler-cli/src/ngtsc/annotations/common/src

packages/compiler-cli/src/ngtsc/annotations/common/src/metadata.ts

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {ErrorCode, FatalDiagnosticError, makeRelatedInformation} from '../../../diagnostics';
9+
import {ErrorCode, FatalDiagnosticError} from '../../../diagnostics';
1010
import {
1111
ArrowFunctionExpr,
1212
Expression,
@@ -19,6 +19,7 @@ import {
1919
import ts from 'typescript';
2020

2121
import {
22+
ClassMember,
2223
ClassMemberAccessLevel,
2324
CtorParameter,
2425
DeclarationNode,
@@ -88,15 +89,32 @@ export function extractClassMetadata(
8889
const classMembers = reflection.getMembersOfClass(clazz).filter(
8990
(member) =>
9091
!member.isStatic &&
91-
member.decorators !== null &&
92-
member.decorators.length > 0 &&
9392
// Private fields are not supported in the metadata emit
9493
member.accessLevel !== ClassMemberAccessLevel.EcmaScriptPrivate,
9594
);
96-
const duplicateDecoratedMembers = classMembers.filter(
97-
(member, i, arr) => arr.findIndex((arrayMember) => arrayMember.name === member.name) < i,
98-
);
99-
if (duplicateDecoratedMembers.length > 0) {
95+
96+
const decoratedMembers: {key: string; value: Expression; quoted: boolean}[] = [];
97+
const seenMemberNames = new Set<string>();
98+
let duplicateDecoratedMembers: ClassMember[] | null = null;
99+
100+
for (const member of classMembers) {
101+
if (member.decorators !== null && member.decorators.length > 0) {
102+
decoratedMembers.push({
103+
key: member.name,
104+
quoted: false,
105+
value: decoratedClassMemberToMetadata(member.decorators!, isCore),
106+
});
107+
108+
if (seenMemberNames.has(member.name)) {
109+
duplicateDecoratedMembers ??= [];
110+
duplicateDecoratedMembers.push(member);
111+
} else {
112+
seenMemberNames.add(member.name);
113+
}
114+
}
115+
}
116+
117+
if (duplicateDecoratedMembers !== null) {
100118
// This should theoretically never happen, because the only way to have duplicate instance
101119
// member names is getter/setter pairs and decorators cannot appear in both a getter and the
102120
// corresponding setter.
@@ -107,13 +125,9 @@ export function extractClassMetadata(
107125
duplicateDecoratedMembers.map((member) => member.name).join(', '),
108126
);
109127
}
110-
const decoratedMembers = classMembers.map((member) =>
111-
classMemberToMetadata(member.nameNode ?? member.name, member.decorators!, isCore),
112-
);
128+
113129
if (decoratedMembers.length > 0) {
114-
metaPropDecorators = new WrappedNodeExpr(
115-
ts.factory.createObjectLiteralExpression(decoratedMembers),
116-
);
130+
metaPropDecorators = literalMap(decoratedMembers);
117131
}
118132

119133
return {
@@ -153,16 +167,14 @@ function ctorParameterToMetadata(param: CtorParameter, isCore: boolean): Express
153167
/**
154168
* Convert a reflected class member to metadata.
155169
*/
156-
function classMemberToMetadata(
157-
name: ts.PropertyName | string,
170+
function decoratedClassMemberToMetadata(
158171
decorators: Decorator[],
159172
isCore: boolean,
160-
): ts.PropertyAssignment {
173+
): LiteralArrayExpr {
161174
const ngDecorators = decorators
162175
.filter((dec) => isAngularDecorator(dec, isCore))
163-
.map((decorator: Decorator) => decoratorToMetadata(decorator));
164-
const decoratorMeta = ts.factory.createArrayLiteralExpression(ngDecorators);
165-
return ts.factory.createPropertyAssignment(name, decoratorMeta);
176+
.map((decorator: Decorator) => new WrappedNodeExpr(decoratorToMetadata(decorator)));
177+
return new LiteralArrayExpr(ngDecorators);
166178
}
167179

168180
/**

0 commit comments

Comments
 (0)