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' ;
1010import {
1111 ArrowFunctionExpr ,
1212 Expression ,
@@ -19,6 +19,7 @@ import {
1919import ts from 'typescript' ;
2020
2121import {
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